blob: ff9f914c4896e917c14fafec5532a32f2a136d0e [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
2716 int length = subject->length();
2717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 return isolate->heap()->NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684}
4685
4686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
4689 ASSERT(args.length() == 1);
4690
4691 CONVERT_CHECKED(JSArray, codes, args[0]);
4692 int length = Smi::cast(codes->length())->value();
4693
4694 // Check if the string can be ASCII.
4695 int i;
4696 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004697 Object* element;
4698 { MaybeObject* maybe_element = codes->GetElement(i);
4699 // We probably can't get an exception here, but just in order to enforce
4700 // the checking of inputs in the runtime calls we check here.
4701 if (!maybe_element->ToObject(&element)) return maybe_element;
4702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4704 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4705 break;
4706 }
4707
lrn@chromium.org303ada72010-10-27 09:33:13 +00004708 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 }
4714
lrn@chromium.org303ada72010-10-27 09:33:13 +00004715 Object* object = NULL;
4716 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 String* result = String::cast(object);
4718 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004719 Object* element;
4720 { MaybeObject* maybe_element = codes->GetElement(i);
4721 if (!maybe_element->ToObject(&element)) return maybe_element;
4722 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004724 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 }
4726 return result;
4727}
4728
4729
4730// kNotEscaped is generated by the following:
4731//
4732// #!/bin/perl
4733// for (my $i = 0; $i < 256; $i++) {
4734// print "\n" if $i % 16 == 0;
4735// my $c = chr($i);
4736// my $escaped = 1;
4737// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4738// print $escaped ? "0, " : "1, ";
4739// }
4740
4741
4742static bool IsNotEscaped(uint16_t character) {
4743 // Only for 8 bit characters, the rest are always escaped (in a different way)
4744 ASSERT(character < 256);
4745 static const char kNotEscaped[256] = {
4746 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4749 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4752 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4753 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4754 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 };
4763 return kNotEscaped[character] != 0;
4764}
4765
4766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004767RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768 const char hex_chars[] = "0123456789ABCDEF";
4769 NoHandleAllocation ha;
4770 ASSERT(args.length() == 1);
4771 CONVERT_CHECKED(String, source, args[0]);
4772
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004773 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774
4775 int escaped_length = 0;
4776 int length = source->length();
4777 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 Access<StringInputBuffer> buffer(
4779 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 buffer->Reset(source);
4781 while (buffer->has_more()) {
4782 uint16_t character = buffer->GetNext();
4783 if (character >= 256) {
4784 escaped_length += 6;
4785 } else if (IsNotEscaped(character)) {
4786 escaped_length++;
4787 } else {
4788 escaped_length += 3;
4789 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004790 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004791 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004792 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 return Failure::OutOfMemoryException();
4795 }
4796 }
4797 }
4798 // No length change implies no change. Return original string if no change.
4799 if (escaped_length == length) {
4800 return source;
4801 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004802 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004803 { MaybeObject* maybe_o =
4804 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 if (!maybe_o->ToObject(&o)) return maybe_o;
4806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 String* destination = String::cast(o);
4808 int dest_position = 0;
4809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004810 Access<StringInputBuffer> buffer(
4811 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 buffer->Rewind();
4813 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004814 uint16_t chr = buffer->GetNext();
4815 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004816 destination->Set(dest_position, '%');
4817 destination->Set(dest_position+1, 'u');
4818 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4819 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4820 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4821 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004823 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004824 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 dest_position++;
4826 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004827 destination->Set(dest_position, '%');
4828 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4829 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 dest_position += 3;
4831 }
4832 }
4833 return destination;
4834}
4835
4836
4837static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4838 static const signed char kHexValue['g'] = {
4839 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4843 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4844 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, 10, 11, 12, 13, 14, 15 };
4846
4847 if (character1 > 'f') return -1;
4848 int hi = kHexValue[character1];
4849 if (hi == -1) return -1;
4850 if (character2 > 'f') return -1;
4851 int lo = kHexValue[character2];
4852 if (lo == -1) return -1;
4853 return (hi << 4) + lo;
4854}
4855
4856
ager@chromium.org870a0b62008-11-04 11:43:05 +00004857static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858 int i,
4859 int length,
4860 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004861 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004862 int32_t hi = 0;
4863 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 if (character == '%' &&
4865 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004866 source->Get(i + 1) == 'u' &&
4867 (hi = TwoDigitHex(source->Get(i + 2),
4868 source->Get(i + 3))) != -1 &&
4869 (lo = TwoDigitHex(source->Get(i + 4),
4870 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004871 *step = 6;
4872 return (hi << 8) + lo;
4873 } else if (character == '%' &&
4874 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004875 (lo = TwoDigitHex(source->Get(i + 1),
4876 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 *step = 3;
4878 return lo;
4879 } else {
4880 *step = 1;
4881 return character;
4882 }
4883}
4884
4885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004886RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 NoHandleAllocation ha;
4888 ASSERT(args.length() == 1);
4889 CONVERT_CHECKED(String, source, args[0]);
4890
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004891 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892
4893 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004894 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895
4896 int unescaped_length = 0;
4897 for (int i = 0; i < length; unescaped_length++) {
4898 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004899 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004901 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 i += step;
4903 }
4904
4905 // No length change implies no change. Return original string if no change.
4906 if (unescaped_length == length)
4907 return source;
4908
lrn@chromium.org303ada72010-10-27 09:33:13 +00004909 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004910 { MaybeObject* maybe_o =
4911 ascii ?
4912 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4913 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 if (!maybe_o->ToObject(&o)) return maybe_o;
4915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 String* destination = String::cast(o);
4917
4918 int dest_position = 0;
4919 for (int i = 0; i < length; dest_position++) {
4920 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004921 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922 i += step;
4923 }
4924 return destination;
4925}
4926
4927
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004928static const unsigned int kQuoteTableLength = 128u;
4929
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004930static const int kJsonQuotesCharactersPerEntry = 8;
4931static const char* const JsonQuotes =
4932 "\\u0000 \\u0001 \\u0002 \\u0003 "
4933 "\\u0004 \\u0005 \\u0006 \\u0007 "
4934 "\\b \\t \\n \\u000b "
4935 "\\f \\r \\u000e \\u000f "
4936 "\\u0010 \\u0011 \\u0012 \\u0013 "
4937 "\\u0014 \\u0015 \\u0016 \\u0017 "
4938 "\\u0018 \\u0019 \\u001a \\u001b "
4939 "\\u001c \\u001d \\u001e \\u001f "
4940 " ! \\\" # "
4941 "$ % & ' "
4942 "( ) * + "
4943 ", - . / "
4944 "0 1 2 3 "
4945 "4 5 6 7 "
4946 "8 9 : ; "
4947 "< = > ? "
4948 "@ A B C "
4949 "D E F G "
4950 "H I J K "
4951 "L M N O "
4952 "P Q R S "
4953 "T U V W "
4954 "X Y Z [ "
4955 "\\\\ ] ^ _ "
4956 "` a b c "
4957 "d e f g "
4958 "h i j k "
4959 "l m n o "
4960 "p q r s "
4961 "t u v w "
4962 "x y z { "
4963 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004964
4965
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004966// For a string that is less than 32k characters it should always be
4967// possible to allocate it in new space.
4968static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4969
4970
4971// Doing JSON quoting cannot make the string more than this many times larger.
4972static const int kJsonQuoteWorstCaseBlowup = 6;
4973
4974
4975// Covers the entire ASCII range (all other characters are unchanged by JSON
4976// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004977static const byte JsonQuoteLengths[kQuoteTableLength] = {
4978 6, 6, 6, 6, 6, 6, 6, 6,
4979 2, 2, 2, 6, 2, 2, 6, 6,
4980 6, 6, 6, 6, 6, 6, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 1, 1, 2, 1, 1, 1, 1, 1,
4983 1, 1, 1, 1, 1, 1, 1, 1,
4984 1, 1, 1, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 2, 1, 1, 1,
4990 1, 1, 1, 1, 1, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994};
4995
4996
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004997template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999
5000
5001template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5003 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005004}
5005
5006
5007template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005008MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5009 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005010}
5011
5012
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005013template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5015 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005016 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005017 const Char* read_cursor = characters.start();
5018 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005019 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005020 int quoted_length = kSpaceForQuotes;
5021 while (read_cursor < end) {
5022 Char c = *(read_cursor++);
5023 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5024 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005025 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005026 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027 }
5028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005029 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5030 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005031 Object* new_object;
5032 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005033 return new_alloc;
5034 }
5035 StringType* new_string = StringType::cast(new_object);
5036
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005037 Char* write_cursor = reinterpret_cast<Char*>(
5038 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005039 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005040 *(write_cursor++) = '"';
5041
5042 read_cursor = characters.start();
5043 while (read_cursor < end) {
5044 Char c = *(read_cursor++);
5045 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5046 *(write_cursor++) = c;
5047 } else {
5048 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5049 const char* replacement = JsonQuotes +
5050 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5051 for (int i = 0; i < len; i++) {
5052 *write_cursor++ = *replacement++;
5053 }
5054 }
5055 }
5056 *(write_cursor++) = '"';
5057 return new_string;
5058}
5059
5060
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005061template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062static MaybeObject* QuoteJsonString(Isolate* isolate,
5063 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005064 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005066 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005067 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5068 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005069 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005070 }
5071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5073 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005074 Object* new_object;
5075 if (!new_alloc->ToObject(&new_object)) {
5076 return new_alloc;
5077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079 // Even if our string is small enough to fit in new space we still have to
5080 // handle it being allocated in old space as may happen in the third
5081 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5082 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005083 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005084 }
5085 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005086 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087
5088 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5089 Char* write_cursor = reinterpret_cast<Char*>(
5090 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005091 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005093
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005094 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005095 const Char* end = read_cursor + length;
5096 while (read_cursor < end) {
5097 Char c = *(read_cursor++);
5098 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5099 *(write_cursor++) = c;
5100 } else {
5101 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5102 const char* replacement = JsonQuotes +
5103 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5104 write_cursor[0] = replacement[0];
5105 if (len > 1) {
5106 write_cursor[1] = replacement[1];
5107 if (len > 2) {
5108 ASSERT(len == 6);
5109 write_cursor[2] = replacement[2];
5110 write_cursor[3] = replacement[3];
5111 write_cursor[4] = replacement[4];
5112 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113 }
5114 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005115 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005116 }
5117 }
5118 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005119
5120 int final_length = static_cast<int>(
5121 write_cursor - reinterpret_cast<Char*>(
5122 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005123 isolate->heap()->new_space()->
5124 template ShrinkStringAtAllocationBoundary<StringType>(
5125 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126 return new_string;
5127}
5128
5129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005130RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005131 NoHandleAllocation ha;
5132 CONVERT_CHECKED(String, str, args[0]);
5133 if (!str->IsFlat()) {
5134 MaybeObject* try_flatten = str->TryFlatten();
5135 Object* flat;
5136 if (!try_flatten->ToObject(&flat)) {
5137 return try_flatten;
5138 }
5139 str = String::cast(flat);
5140 ASSERT(str->IsFlat());
5141 }
5142 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5144 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005146 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5147 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005148 }
5149}
5150
5151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005152RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005153 NoHandleAllocation ha;
5154 CONVERT_CHECKED(String, str, args[0]);
5155 if (!str->IsFlat()) {
5156 MaybeObject* try_flatten = str->TryFlatten();
5157 Object* flat;
5158 if (!try_flatten->ToObject(&flat)) {
5159 return try_flatten;
5160 }
5161 str = String::cast(flat);
5162 ASSERT(str->IsFlat());
5163 }
5164 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5166 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005167 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005168 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5169 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005170 }
5171}
5172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005173RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174 NoHandleAllocation ha;
5175
5176 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005177 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005179 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
lrn@chromium.org25156de2010-04-06 13:10:27 +00005181 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5182 double value = StringToInt(s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005183 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184}
5185
5186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005187RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 NoHandleAllocation ha;
5189 CONVERT_CHECKED(String, str, args[0]);
5190
5191 // ECMA-262 section 15.1.2.3, empty string is NaN
5192 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5193
5194 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196}
5197
5198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005200MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202 String* s,
5203 int length,
5204 int input_string_length,
5205 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005206 // We try this twice, once with the assumption that the result is no longer
5207 // than the input and, if that assumption breaks, again with the exact
5208 // length. This may not be pretty, but it is nicer than what was here before
5209 // and I hereby claim my vaffel-is.
5210 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 // Allocate the resulting string.
5212 //
5213 // NOTE: This assumes that the upper/lower case of an ascii
5214 // character is also ascii. This is currently the case, but it
5215 // might break in the future if we implement more context and locale
5216 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005217 Object* o;
5218 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 ? isolate->heap()->AllocateRawAsciiString(length)
5220 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 if (!maybe_o->ToObject(&o)) return maybe_o;
5222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 String* result = String::cast(o);
5224 bool has_changed_character = false;
5225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 // Convert all characters to upper case, assuming that they will fit
5227 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 Access<StringInputBuffer> buffer(
5229 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005231 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 // We can assume that the string is not empty
5233 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005234 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005235 bool has_next = buffer->has_more();
5236 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 int char_length = mapping->get(current, next, chars);
5238 if (char_length == 0) {
5239 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005240 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 i++;
5242 } else if (char_length == 1) {
5243 // Common case: converting the letter resulted in one character.
5244 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005245 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 has_changed_character = true;
5247 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005248 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249 // We've assumed that the result would be as long as the
5250 // input but here is a character that converts to several
5251 // characters. No matter, we calculate the exact length
5252 // of the result and try the whole thing again.
5253 //
5254 // Note that this leaves room for optimization. We could just
5255 // memcpy what we already have to the result string. Also,
5256 // the result string is the last object allocated we could
5257 // "realloc" it and probably, in the vast majority of cases,
5258 // extend the existing string to be able to hold the full
5259 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005260 int next_length = 0;
5261 if (has_next) {
5262 next_length = mapping->get(next, 0, chars);
5263 if (next_length == 0) next_length = 1;
5264 }
5265 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 while (buffer->has_more()) {
5267 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005268 // NOTE: we use 0 as the next character here because, while
5269 // the next character may affect what a character converts to,
5270 // it does not in any case affect the length of what it convert
5271 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005272 int char_length = mapping->get(current, 0, chars);
5273 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005274 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005275 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 return Failure::OutOfMemoryException();
5278 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005279 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 // Try again with the real length.
5281 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 } else {
5283 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005284 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 i++;
5286 }
5287 has_changed_character = true;
5288 }
5289 current = next;
5290 }
5291 if (has_changed_character) {
5292 return result;
5293 } else {
5294 // If we didn't actually change anything in doing the conversion
5295 // we simple return the result and let the converted string
5296 // become garbage; there is no reason to keep two identical strings
5297 // alive.
5298 return s;
5299 }
5300}
5301
5302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005303namespace {
5304
lrn@chromium.org303ada72010-10-27 09:33:13 +00005305static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5306
5307
5308// Given a word and two range boundaries returns a word with high bit
5309// set in every byte iff the corresponding input byte was strictly in
5310// the range (m, n). All the other bits in the result are cleared.
5311// This function is only useful when it can be inlined and the
5312// boundaries are statically known.
5313// Requires: all bytes in the input word and the boundaries must be
5314// ascii (less than 0x7F).
5315static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5316 // Every byte in an ascii string is less than or equal to 0x7F.
5317 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5318 // Use strict inequalities since in edge cases the function could be
5319 // further simplified.
5320 ASSERT(0 < m && m < n && n < 0x7F);
5321 // Has high bit set in every w byte less than n.
5322 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5323 // Has high bit set in every w byte greater than m.
5324 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5325 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5326}
5327
5328
5329enum AsciiCaseConversion {
5330 ASCII_TO_LOWER,
5331 ASCII_TO_UPPER
5332};
5333
5334
5335template <AsciiCaseConversion dir>
5336struct FastAsciiConverter {
5337 static bool Convert(char* dst, char* src, int length) {
5338#ifdef DEBUG
5339 char* saved_dst = dst;
5340 char* saved_src = src;
5341#endif
5342 // We rely on the distance between upper and lower case letters
5343 // being a known power of 2.
5344 ASSERT('a' - 'A' == (1 << 5));
5345 // Boundaries for the range of input characters than require conversion.
5346 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5347 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5348 bool changed = false;
5349 char* const limit = src + length;
5350#ifdef V8_HOST_CAN_READ_UNALIGNED
5351 // Process the prefix of the input that requires no conversion one
5352 // (machine) word at a time.
5353 while (src <= limit - sizeof(uintptr_t)) {
5354 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5355 if (AsciiRangeMask(w, lo, hi) != 0) {
5356 changed = true;
5357 break;
5358 }
5359 *reinterpret_cast<uintptr_t*>(dst) = w;
5360 src += sizeof(uintptr_t);
5361 dst += sizeof(uintptr_t);
5362 }
5363 // Process the remainder of the input performing conversion when
5364 // required one word at a time.
5365 while (src <= limit - sizeof(uintptr_t)) {
5366 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5367 uintptr_t m = AsciiRangeMask(w, lo, hi);
5368 // The mask has high (7th) bit set in every byte that needs
5369 // conversion and we know that the distance between cases is
5370 // 1 << 5.
5371 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5372 src += sizeof(uintptr_t);
5373 dst += sizeof(uintptr_t);
5374 }
5375#endif
5376 // Process the last few bytes of the input (or the whole input if
5377 // unaligned access is not supported).
5378 while (src < limit) {
5379 char c = *src;
5380 if (lo < c && c < hi) {
5381 c ^= (1 << 5);
5382 changed = true;
5383 }
5384 *dst = c;
5385 ++src;
5386 ++dst;
5387 }
5388#ifdef DEBUG
5389 CheckConvert(saved_dst, saved_src, length, changed);
5390#endif
5391 return changed;
5392 }
5393
5394#ifdef DEBUG
5395 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5396 bool expected_changed = false;
5397 for (int i = 0; i < length; i++) {
5398 if (dst[i] == src[i]) continue;
5399 expected_changed = true;
5400 if (dir == ASCII_TO_LOWER) {
5401 ASSERT('A' <= src[i] && src[i] <= 'Z');
5402 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5403 } else {
5404 ASSERT(dir == ASCII_TO_UPPER);
5405 ASSERT('a' <= src[i] && src[i] <= 'z');
5406 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5407 }
5408 }
5409 ASSERT(expected_changed == changed);
5410 }
5411#endif
5412};
5413
5414
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415struct ToLowerTraits {
5416 typedef unibrow::ToLowercase UnibrowConverter;
5417
lrn@chromium.org303ada72010-10-27 09:33:13 +00005418 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005419};
5420
5421
5422struct ToUpperTraits {
5423 typedef unibrow::ToUppercase UnibrowConverter;
5424
lrn@chromium.org303ada72010-10-27 09:33:13 +00005425 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005426};
5427
5428} // namespace
5429
5430
5431template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005432MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005433 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005436 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005437 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005438 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 if (length == 0) return s;
5443
5444 // Simpler handling of ascii strings.
5445 //
5446 // NOTE: This assumes that the upper/lower case of an ascii
5447 // character is also ascii. This is currently the case, but it
5448 // might break in the future if we implement more context and locale
5449 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005450 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005451 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 if (!maybe_o->ToObject(&o)) return maybe_o;
5454 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005455 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005456 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005457 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 return has_changed_character ? result : s;
5459 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005460
lrn@chromium.org303ada72010-10-27 09:33:13 +00005461 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005462 { MaybeObject* maybe_answer =
5463 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5465 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005466 if (answer->IsSmi()) {
5467 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005468 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005469 ConvertCaseHelper(isolate,
5470 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005474 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475}
5476
5477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005478RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005479 return ConvertCase<ToLowerTraits>(
5480 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481}
5482
5483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005484RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005485 return ConvertCase<ToUpperTraits>(
5486 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487}
5488
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005489
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005490static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5491 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5492}
5493
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005495RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005496 NoHandleAllocation ha;
5497 ASSERT(args.length() == 3);
5498
5499 CONVERT_CHECKED(String, s, args[0]);
5500 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5501 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5502
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005503 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005504 int length = s->length();
5505
5506 int left = 0;
5507 if (trimLeft) {
5508 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5509 left++;
5510 }
5511 }
5512
5513 int right = length;
5514 if (trimRight) {
5515 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5516 right--;
5517 }
5518 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005519 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005520}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005522
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005523template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005524void FindStringIndices(Isolate* isolate,
5525 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005526 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005527 ZoneList<int>* indices,
5528 unsigned int limit) {
5529 ASSERT(limit > 0);
5530 // Collect indices of pattern in subject, and the end-of-string index.
5531 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005532 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005533 int pattern_length = pattern.length();
5534 int index = 0;
5535 while (limit > 0) {
5536 index = search.Search(subject, index);
5537 if (index < 0) return;
5538 indices->Add(index);
5539 index += pattern_length;
5540 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005541 }
5542}
5543
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005545RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005547 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 CONVERT_ARG_CHECKED(String, subject, 0);
5549 CONVERT_ARG_CHECKED(String, pattern, 1);
5550 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5551
5552 int subject_length = subject->length();
5553 int pattern_length = pattern->length();
5554 RUNTIME_ASSERT(pattern_length > 0);
5555
5556 // The limit can be very large (0xffffffffu), but since the pattern
5557 // isn't empty, we can never create more parts than ~half the length
5558 // of the subject.
5559
5560 if (!subject->IsFlat()) FlattenString(subject);
5561
5562 static const int kMaxInitialListCapacity = 16;
5563
5564 ZoneScope scope(DELETE_ON_EXIT);
5565
5566 // Find (up to limit) indices of separator and end-of-string in subject
5567 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5568 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005569 if (!pattern->IsFlat()) FlattenString(pattern);
5570
5571 // No allocation block.
5572 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005573 AssertNoAllocation nogc;
5574 if (subject->IsAsciiRepresentation()) {
5575 Vector<const char> subject_vector = subject->ToAsciiVector();
5576 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005577 FindStringIndices(isolate,
5578 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005579 pattern->ToAsciiVector(),
5580 &indices,
5581 limit);
5582 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005583 FindStringIndices(isolate,
5584 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005585 pattern->ToUC16Vector(),
5586 &indices,
5587 limit);
5588 }
5589 } else {
5590 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5591 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 FindStringIndices(isolate,
5593 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005594 pattern->ToAsciiVector(),
5595 &indices,
5596 limit);
5597 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 FindStringIndices(isolate,
5599 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005600 pattern->ToUC16Vector(),
5601 &indices,
5602 limit);
5603 }
5604 }
5605 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005606
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005607 if (static_cast<uint32_t>(indices.length()) < limit) {
5608 indices.Add(subject_length);
5609 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005610
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005611 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
5613 // Create JSArray of substrings separated by separator.
5614 int part_count = indices.length();
5615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005616 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005617 result->set_length(Smi::FromInt(part_count));
5618
5619 ASSERT(result->HasFastElements());
5620
5621 if (part_count == 1 && indices.at(0) == subject_length) {
5622 FixedArray::cast(result->elements())->set(0, *subject);
5623 return *result;
5624 }
5625
5626 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5627 int part_start = 0;
5628 for (int i = 0; i < part_count; i++) {
5629 HandleScope local_loop_handle;
5630 int part_end = indices.at(i);
5631 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005632 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005633 elements->set(i, *substring);
5634 part_start = part_end + pattern_length;
5635 }
5636
5637 return *result;
5638}
5639
5640
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641// Copies ascii characters to the given fixed array looking up
5642// one-char strings in the cache. Gives up on the first char that is
5643// not in the cache and fills the remainder with smi zeros. Returns
5644// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005645static int CopyCachedAsciiCharsToArray(Heap* heap,
5646 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005647 FixedArray* elements,
5648 int length) {
5649 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005650 FixedArray* ascii_cache = heap->single_character_string_cache();
5651 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005652 int i;
5653 for (i = 0; i < length; ++i) {
5654 Object* value = ascii_cache->get(chars[i]);
5655 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005656 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005657 elements->set(i, value, SKIP_WRITE_BARRIER);
5658 }
5659 if (i < length) {
5660 ASSERT(Smi::FromInt(0) == 0);
5661 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5662 }
5663#ifdef DEBUG
5664 for (int j = 0; j < length; ++j) {
5665 Object* element = elements->get(j);
5666 ASSERT(element == Smi::FromInt(0) ||
5667 (element->IsString() && String::cast(element)->LooksValid()));
5668 }
5669#endif
5670 return i;
5671}
5672
5673
5674// Converts a String to JSArray.
5675// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005676RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005678 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005679 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681
5682 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005683 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684
5685 Handle<FixedArray> elements;
5686 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005687 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005688 { MaybeObject* maybe_obj =
5689 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005692 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005693
5694 Vector<const char> chars = s->ToAsciiVector();
5695 // Note, this will initialize all elements (not only the prefix)
5696 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005697 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5698 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005699 *elements,
5700 length);
5701
5702 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005703 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5704 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005705 }
5706 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005707 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005709 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5710 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 }
5712 }
5713
5714#ifdef DEBUG
5715 for (int i = 0; i < length; ++i) {
5716 ASSERT(String::cast(elements->get(i))->length() == 1);
5717 }
5718#endif
5719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005721}
5722
5723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005724RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005725 NoHandleAllocation ha;
5726 ASSERT(args.length() == 1);
5727 CONVERT_CHECKED(String, value, args[0]);
5728 return value->ToObject();
5729}
5730
5731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005733 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 return char_length == 0;
5736}
5737
5738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005739RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 NoHandleAllocation ha;
5741 ASSERT(args.length() == 1);
5742
5743 Object* number = args[0];
5744 RUNTIME_ASSERT(number->IsNumber());
5745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747}
5748
5749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005750RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005751 NoHandleAllocation ha;
5752 ASSERT(args.length() == 1);
5753
5754 Object* number = args[0];
5755 RUNTIME_ASSERT(number->IsNumber());
5756
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005758}
5759
5760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005761RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005762 NoHandleAllocation ha;
5763 ASSERT(args.length() == 1);
5764
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005765 CONVERT_DOUBLE_CHECKED(number, args[0]);
5766
5767 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5768 if (number > 0 && number <= Smi::kMaxValue) {
5769 return Smi::FromInt(static_cast<int>(number));
5770 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005772}
5773
5774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005775RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005776 NoHandleAllocation ha;
5777 ASSERT(args.length() == 1);
5778
5779 CONVERT_DOUBLE_CHECKED(number, args[0]);
5780
5781 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5782 if (number > 0 && number <= Smi::kMaxValue) {
5783 return Smi::FromInt(static_cast<int>(number));
5784 }
5785
5786 double double_value = DoubleToInteger(number);
5787 // Map both -0 and +0 to +0.
5788 if (double_value == 0) double_value = 0;
5789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005791}
5792
5793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005794RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005795 NoHandleAllocation ha;
5796 ASSERT(args.length() == 1);
5797
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005799 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804 NoHandleAllocation ha;
5805 ASSERT(args.length() == 1);
5806
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005807 CONVERT_DOUBLE_CHECKED(number, args[0]);
5808
5809 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5810 if (number > 0 && number <= Smi::kMaxValue) {
5811 return Smi::FromInt(static_cast<int>(number));
5812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
ager@chromium.org870a0b62008-11-04 11:43:05 +00005817// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5818// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005819RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005820 NoHandleAllocation ha;
5821 ASSERT(args.length() == 1);
5822
5823 Object* obj = args[0];
5824 if (obj->IsSmi()) {
5825 return obj;
5826 }
5827 if (obj->IsHeapNumber()) {
5828 double value = HeapNumber::cast(obj)->value();
5829 int int_value = FastD2I(value);
5830 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5831 return Smi::FromInt(int_value);
5832 }
5833 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005834 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005835}
5836
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005838RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005839 NoHandleAllocation ha;
5840 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005841 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005842}
5843
5844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005845RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 NoHandleAllocation ha;
5847 ASSERT(args.length() == 2);
5848
5849 CONVERT_DOUBLE_CHECKED(x, args[0]);
5850 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852}
5853
5854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 NoHandleAllocation ha;
5857 ASSERT(args.length() == 2);
5858
5859 CONVERT_DOUBLE_CHECKED(x, args[0]);
5860 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005861 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005862}
5863
5864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005865RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 NoHandleAllocation ha;
5867 ASSERT(args.length() == 2);
5868
5869 CONVERT_DOUBLE_CHECKED(x, args[0]);
5870 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872}
5873
5874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005875RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 1);
5878
5879 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881}
5882
5883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005884RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005885 NoHandleAllocation ha;
5886 ASSERT(args.length() == 0);
5887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005888 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005889}
5890
5891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005892RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893 NoHandleAllocation ha;
5894 ASSERT(args.length() == 2);
5895
5896 CONVERT_DOUBLE_CHECKED(x, args[0]);
5897 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899}
5900
5901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005902RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 NoHandleAllocation ha;
5904 ASSERT(args.length() == 2);
5905
5906 CONVERT_DOUBLE_CHECKED(x, args[0]);
5907 CONVERT_DOUBLE_CHECKED(y, args[1]);
5908
ager@chromium.org3811b432009-10-28 14:53:37 +00005909 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005910 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 NoHandleAllocation ha;
5917 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 CONVERT_CHECKED(String, str1, args[0]);
5919 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 isolate->counters()->string_add_runtime()->Increment();
5921 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922}
5923
5924
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005925template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005926static inline void StringBuilderConcatHelper(String* special,
5927 sinkchar* sink,
5928 FixedArray* fixed_array,
5929 int array_length) {
5930 int position = 0;
5931 for (int i = 0; i < array_length; i++) {
5932 Object* element = fixed_array->get(i);
5933 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005934 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005935 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 int pos;
5937 int len;
5938 if (encoded_slice > 0) {
5939 // Position and length encoded in one smi.
5940 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5941 len = StringBuilderSubstringLength::decode(encoded_slice);
5942 } else {
5943 // Position and length encoded in two smis.
5944 Object* obj = fixed_array->get(++i);
5945 ASSERT(obj->IsSmi());
5946 pos = Smi::cast(obj)->value();
5947 len = -encoded_slice;
5948 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005949 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005950 sink + position,
5951 pos,
5952 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005953 position += len;
5954 } else {
5955 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005956 int element_length = string->length();
5957 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005958 position += element_length;
5959 }
5960 }
5961}
5962
5963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005964RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005966 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 return Failure::OutOfMemoryException();
5971 }
5972 int array_length = Smi::cast(args[1])->value();
5973 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005974
5975 // This assumption is used by the slice encoding in one or two smis.
5976 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5977
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005978 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005980 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 }
5982 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005983 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986
5987 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 } else if (array_length == 1) {
5990 Object* first = fixed_array->get(0);
5991 if (first->IsString()) return first;
5992 }
5993
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005994 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 int position = 0;
5996 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005997 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 Object* elt = fixed_array->get(i);
5999 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006000 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006001 int smi_value = Smi::cast(elt)->value();
6002 int pos;
6003 int len;
6004 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006005 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006006 pos = StringBuilderSubstringPosition::decode(smi_value);
6007 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006008 } else {
6009 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006010 len = -smi_value;
6011 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006012 i++;
6013 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006015 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006016 Object* next_smi = fixed_array->get(i);
6017 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006019 }
6020 pos = Smi::cast(next_smi)->value();
6021 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006022 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006025 ASSERT(pos >= 0);
6026 ASSERT(len >= 0);
6027 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006029 }
6030 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 } else if (elt->IsString()) {
6032 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006034 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006035 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006039 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006041 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006043 return Failure::OutOfMemoryException();
6044 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006045 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 }
6047
6048 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 { MaybeObject* maybe_object =
6053 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006054 if (!maybe_object->ToObject(&object)) return maybe_object;
6055 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006056 SeqAsciiString* answer = SeqAsciiString::cast(object);
6057 StringBuilderConcatHelper(special,
6058 answer->GetChars(),
6059 fixed_array,
6060 array_length);
6061 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063 { MaybeObject* maybe_object =
6064 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006065 if (!maybe_object->ToObject(&object)) return maybe_object;
6066 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006067 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6068 StringBuilderConcatHelper(special,
6069 answer->GetChars(),
6070 fixed_array,
6071 array_length);
6072 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074}
6075
6076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006077RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006078 NoHandleAllocation ha;
6079 ASSERT(args.length() == 3);
6080 CONVERT_CHECKED(JSArray, array, args[0]);
6081 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006082 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006083 return Failure::OutOfMemoryException();
6084 }
6085 int array_length = Smi::cast(args[1])->value();
6086 CONVERT_CHECKED(String, separator, args[2]);
6087
6088 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006090 }
6091 FixedArray* fixed_array = FixedArray::cast(array->elements());
6092 if (fixed_array->length() < array_length) {
6093 array_length = fixed_array->length();
6094 }
6095
6096 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006097 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006098 } else if (array_length == 1) {
6099 Object* first = fixed_array->get(0);
6100 if (first->IsString()) return first;
6101 }
6102
6103 int separator_length = separator->length();
6104 int max_nof_separators =
6105 (String::kMaxLength + separator_length - 1) / separator_length;
6106 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006107 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006108 return Failure::OutOfMemoryException();
6109 }
6110 int length = (array_length - 1) * separator_length;
6111 for (int i = 0; i < array_length; i++) {
6112 Object* element_obj = fixed_array->get(i);
6113 if (!element_obj->IsString()) {
6114 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006116 }
6117 String* element = String::cast(element_obj);
6118 int increment = element->length();
6119 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006121 return Failure::OutOfMemoryException();
6122 }
6123 length += increment;
6124 }
6125
6126 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 { MaybeObject* maybe_object =
6128 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006129 if (!maybe_object->ToObject(&object)) return maybe_object;
6130 }
6131 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6132
6133 uc16* sink = answer->GetChars();
6134#ifdef DEBUG
6135 uc16* end = sink + length;
6136#endif
6137
6138 String* first = String::cast(fixed_array->get(0));
6139 int first_length = first->length();
6140 String::WriteToFlat(first, sink, 0, first_length);
6141 sink += first_length;
6142
6143 for (int i = 1; i < array_length; i++) {
6144 ASSERT(sink + separator_length <= end);
6145 String::WriteToFlat(separator, sink, 0, separator_length);
6146 sink += separator_length;
6147
6148 String* element = String::cast(fixed_array->get(i));
6149 int element_length = element->length();
6150 ASSERT(sink + element_length <= end);
6151 String::WriteToFlat(element, sink, 0, element_length);
6152 sink += element_length;
6153 }
6154 ASSERT(sink == end);
6155
6156 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6157 return answer;
6158}
6159
6160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006161RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162 NoHandleAllocation ha;
6163 ASSERT(args.length() == 2);
6164
6165 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6166 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168}
6169
6170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006171RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 NoHandleAllocation ha;
6173 ASSERT(args.length() == 2);
6174
6175 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6176 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006177 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178}
6179
6180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006181RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006182 NoHandleAllocation ha;
6183 ASSERT(args.length() == 2);
6184
6185 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6186 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006187 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188}
6189
6190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006191RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192 NoHandleAllocation ha;
6193 ASSERT(args.length() == 1);
6194
6195 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006196 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197}
6198
6199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006200RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 NoHandleAllocation ha;
6202 ASSERT(args.length() == 2);
6203
6204 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6205 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006206 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207}
6208
6209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006210RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006211 NoHandleAllocation ha;
6212 ASSERT(args.length() == 2);
6213
6214 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6215 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217}
6218
6219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006220RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 NoHandleAllocation ha;
6222 ASSERT(args.length() == 2);
6223
6224 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6225 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227}
6228
6229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006230RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231 NoHandleAllocation ha;
6232 ASSERT(args.length() == 2);
6233
6234 CONVERT_DOUBLE_CHECKED(x, args[0]);
6235 CONVERT_DOUBLE_CHECKED(y, args[1]);
6236 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6237 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6238 if (x == y) return Smi::FromInt(EQUAL);
6239 Object* result;
6240 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6241 result = Smi::FromInt(EQUAL);
6242 } else {
6243 result = Smi::FromInt(NOT_EQUAL);
6244 }
6245 return result;
6246}
6247
6248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006249RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 NoHandleAllocation ha;
6251 ASSERT(args.length() == 2);
6252
6253 CONVERT_CHECKED(String, x, args[0]);
6254 CONVERT_CHECKED(String, y, args[1]);
6255
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006256 bool not_equal = !x->Equals(y);
6257 // This is slightly convoluted because the value that signifies
6258 // equality is 0 and inequality is 1 so we have to negate the result
6259 // from String::Equals.
6260 ASSERT(not_equal == 0 || not_equal == 1);
6261 STATIC_CHECK(EQUAL == 0);
6262 STATIC_CHECK(NOT_EQUAL == 1);
6263 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006267RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 NoHandleAllocation ha;
6269 ASSERT(args.length() == 3);
6270
6271 CONVERT_DOUBLE_CHECKED(x, args[0]);
6272 CONVERT_DOUBLE_CHECKED(y, args[1]);
6273 if (isnan(x) || isnan(y)) return args[2];
6274 if (x == y) return Smi::FromInt(EQUAL);
6275 if (isless(x, y)) return Smi::FromInt(LESS);
6276 return Smi::FromInt(GREATER);
6277}
6278
6279
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006280// Compare two Smis as if they were converted to strings and then
6281// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006282RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006283 NoHandleAllocation ha;
6284 ASSERT(args.length() == 2);
6285
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006286 // Extract the integer values from the Smis.
6287 CONVERT_CHECKED(Smi, x, args[0]);
6288 CONVERT_CHECKED(Smi, y, args[1]);
6289 int x_value = x->value();
6290 int y_value = y->value();
6291
6292 // If the integers are equal so are the string representations.
6293 if (x_value == y_value) return Smi::FromInt(EQUAL);
6294
6295 // If one of the integers are zero the normal integer order is the
6296 // same as the lexicographic order of the string representations.
6297 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6298
ager@chromium.org32912102009-01-16 10:38:43 +00006299 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006300 // smallest because the char code of '-' is less than the char code
6301 // of any digit. Otherwise, we make both values positive.
6302 if (x_value < 0 || y_value < 0) {
6303 if (y_value >= 0) return Smi::FromInt(LESS);
6304 if (x_value >= 0) return Smi::FromInt(GREATER);
6305 x_value = -x_value;
6306 y_value = -y_value;
6307 }
6308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 // Arrays for the individual characters of the two Smis. Smis are
6310 // 31 bit integers and 10 decimal digits are therefore enough.
6311 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6312 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6313 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6314
6315
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006316 // Convert the integers to arrays of their decimal digits.
6317 int x_index = 0;
6318 int y_index = 0;
6319 while (x_value > 0) {
6320 x_elms[x_index++] = x_value % 10;
6321 x_value /= 10;
6322 }
6323 while (y_value > 0) {
6324 y_elms[y_index++] = y_value % 10;
6325 y_value /= 10;
6326 }
6327
6328 // Loop through the arrays of decimal digits finding the first place
6329 // where they differ.
6330 while (--x_index >= 0 && --y_index >= 0) {
6331 int diff = x_elms[x_index] - y_elms[y_index];
6332 if (diff != 0) return Smi::FromInt(diff);
6333 }
6334
6335 // If one array is a suffix of the other array, the longest array is
6336 // the representation of the largest of the Smis in the
6337 // lexicographic ordering.
6338 return Smi::FromInt(x_index - y_index);
6339}
6340
6341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006342static Object* StringInputBufferCompare(RuntimeState* state,
6343 String* x,
6344 String* y) {
6345 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6346 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006347 bufx.Reset(x);
6348 bufy.Reset(y);
6349 while (bufx.has_more() && bufy.has_more()) {
6350 int d = bufx.GetNext() - bufy.GetNext();
6351 if (d < 0) return Smi::FromInt(LESS);
6352 else if (d > 0) return Smi::FromInt(GREATER);
6353 }
6354
6355 // x is (non-trivial) prefix of y:
6356 if (bufy.has_more()) return Smi::FromInt(LESS);
6357 // y is prefix of x:
6358 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6359}
6360
6361
6362static Object* FlatStringCompare(String* x, String* y) {
6363 ASSERT(x->IsFlat());
6364 ASSERT(y->IsFlat());
6365 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6366 int prefix_length = x->length();
6367 if (y->length() < prefix_length) {
6368 prefix_length = y->length();
6369 equal_prefix_result = Smi::FromInt(GREATER);
6370 } else if (y->length() > prefix_length) {
6371 equal_prefix_result = Smi::FromInt(LESS);
6372 }
6373 int r;
6374 if (x->IsAsciiRepresentation()) {
6375 Vector<const char> x_chars = x->ToAsciiVector();
6376 if (y->IsAsciiRepresentation()) {
6377 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006378 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379 } else {
6380 Vector<const uc16> y_chars = y->ToUC16Vector();
6381 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6382 }
6383 } else {
6384 Vector<const uc16> x_chars = x->ToUC16Vector();
6385 if (y->IsAsciiRepresentation()) {
6386 Vector<const char> y_chars = y->ToAsciiVector();
6387 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6388 } else {
6389 Vector<const uc16> y_chars = y->ToUC16Vector();
6390 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6391 }
6392 }
6393 Object* result;
6394 if (r == 0) {
6395 result = equal_prefix_result;
6396 } else {
6397 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006399 ASSERT(result ==
6400 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 return result;
6402}
6403
6404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406 NoHandleAllocation ha;
6407 ASSERT(args.length() == 2);
6408
6409 CONVERT_CHECKED(String, x, args[0]);
6410 CONVERT_CHECKED(String, y, args[1]);
6411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006412 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414 // A few fast case tests before we flatten.
6415 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006416 if (y->length() == 0) {
6417 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006418 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006419 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 return Smi::FromInt(LESS);
6421 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006422
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006423 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006424 if (d < 0) return Smi::FromInt(LESS);
6425 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426
lrn@chromium.org303ada72010-10-27 09:33:13 +00006427 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006432 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006435 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006436 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006437}
6438
6439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006440RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 NoHandleAllocation ha;
6442 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006443 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444
6445 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006447}
6448
6449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006450RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006454
6455 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464
6465 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006466 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006467}
6468
6469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470static const double kPiDividedBy4 = 0.78539816339744830962;
6471
6472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006473RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 NoHandleAllocation ha;
6475 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006476 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477
6478 CONVERT_DOUBLE_CHECKED(x, args[0]);
6479 CONVERT_DOUBLE_CHECKED(y, args[1]);
6480 double result;
6481 if (isinf(x) && isinf(y)) {
6482 // Make sure that the result in case of two infinite arguments
6483 // is a multiple of Pi / 4. The sign of the result is determined
6484 // by the first argument (x) and the sign of the second argument
6485 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006486 int multiplier = (x < 0) ? -1 : 1;
6487 if (y < 0) multiplier *= 3;
6488 result = multiplier * kPiDividedBy4;
6489 } else {
6490 result = atan2(x, y);
6491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500
6501 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510
6511 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513}
6514
6515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006516RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520
6521 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006522 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006523}
6524
6525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006526RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527 NoHandleAllocation ha;
6528 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006530
6531 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006532 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533}
6534
6535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540
6541 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550
6551 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006552
6553 // If the second argument is a smi, it is much faster to call the
6554 // custom powi() function than the generic pow().
6555 if (args[1]->IsSmi()) {
6556 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006557 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006558 }
6559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562}
6563
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006564// Fast version of Math.pow if we know that y is not an integer and
6565// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569 CONVERT_DOUBLE_CHECKED(x, args[0]);
6570 CONVERT_DOUBLE_CHECKED(y, args[1]);
6571 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006572 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006573 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006575 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 }
6578}
6579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006586 if (!args[0]->IsHeapNumber()) {
6587 // Must be smi. Return the argument unchanged for all the other types
6588 // to make fuzz-natives test happy.
6589 return args[0];
6590 }
6591
6592 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6593
6594 double value = number->value();
6595 int exponent = number->get_exponent();
6596 int sign = number->get_sign();
6597
6598 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6599 // should be rounded to 2^30, which is not smi.
6600 if (!sign && exponent <= kSmiValueSize - 3) {
6601 return Smi::FromInt(static_cast<int>(value + 0.5));
6602 }
6603
6604 // If the magnitude is big enough, there's no place for fraction part. If we
6605 // try to add 0.5 to this number, 1.0 will be added instead.
6606 if (exponent >= 52) {
6607 return number;
6608 }
6609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006611
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006612 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614}
6615
6616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006617RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 NoHandleAllocation ha;
6619 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006620 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621
6622 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624}
6625
6626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006627RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 NoHandleAllocation ha;
6629 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631
6632 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641
6642 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006643 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644}
6645
6646
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006647static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006648 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6649 181, 212, 243, 273, 304, 334};
6650 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6651 182, 213, 244, 274, 305, 335};
6652
6653 year += month / 12;
6654 month %= 12;
6655 if (month < 0) {
6656 year--;
6657 month += 12;
6658 }
6659
6660 ASSERT(month >= 0);
6661 ASSERT(month < 12);
6662
6663 // year_delta is an arbitrary number such that:
6664 // a) year_delta = -1 (mod 400)
6665 // b) year + year_delta > 0 for years in the range defined by
6666 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6667 // Jan 1 1970. This is required so that we don't run into integer
6668 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006669 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006670 // operations.
6671 static const int year_delta = 399999;
6672 static const int base_day = 365 * (1970 + year_delta) +
6673 (1970 + year_delta) / 4 -
6674 (1970 + year_delta) / 100 +
6675 (1970 + year_delta) / 400;
6676
6677 int year1 = year + year_delta;
6678 int day_from_year = 365 * year1 +
6679 year1 / 4 -
6680 year1 / 100 +
6681 year1 / 400 -
6682 base_day;
6683
6684 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006685 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006686 }
6687
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006688 return day_from_year + day_from_month_leap[month] + day - 1;
6689}
6690
6691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006692RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006693 NoHandleAllocation ha;
6694 ASSERT(args.length() == 3);
6695
6696 CONVERT_SMI_CHECKED(year, args[0]);
6697 CONVERT_SMI_CHECKED(month, args[1]);
6698 CONVERT_SMI_CHECKED(date, args[2]);
6699
6700 return Smi::FromInt(MakeDay(year, month, date));
6701}
6702
6703
6704static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6705static const int kDaysIn4Years = 4 * 365 + 1;
6706static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6707static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6708static const int kDays1970to2000 = 30 * 365 + 7;
6709static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6710 kDays1970to2000;
6711static const int kYearsOffset = 400000;
6712
6713static const char kDayInYear[] = {
6714 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6715 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6717 22, 23, 24, 25, 26, 27, 28,
6718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6719 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6721 22, 23, 24, 25, 26, 27, 28, 29, 30,
6722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6723 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6725 22, 23, 24, 25, 26, 27, 28, 29, 30,
6726 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6727 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6728 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6729 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6730 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6731 22, 23, 24, 25, 26, 27, 28, 29, 30,
6732 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6733 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6734 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6735 22, 23, 24, 25, 26, 27, 28, 29, 30,
6736 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6737 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6738
6739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6740 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6742 22, 23, 24, 25, 26, 27, 28,
6743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6744 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6746 22, 23, 24, 25, 26, 27, 28, 29, 30,
6747 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6748 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6749 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6750 22, 23, 24, 25, 26, 27, 28, 29, 30,
6751 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6752 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6753 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6754 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6755 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6756 22, 23, 24, 25, 26, 27, 28, 29, 30,
6757 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6758 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6759 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6760 22, 23, 24, 25, 26, 27, 28, 29, 30,
6761 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6762 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6763
6764 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6765 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6766 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6767 22, 23, 24, 25, 26, 27, 28, 29,
6768 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6769 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6770 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6771 22, 23, 24, 25, 26, 27, 28, 29, 30,
6772 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6773 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6774 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6775 22, 23, 24, 25, 26, 27, 28, 29, 30,
6776 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6777 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6778 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6779 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6780 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6781 22, 23, 24, 25, 26, 27, 28, 29, 30,
6782 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6783 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6784 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6785 22, 23, 24, 25, 26, 27, 28, 29, 30,
6786 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6787 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6788
6789 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6790 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6791 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6792 22, 23, 24, 25, 26, 27, 28,
6793 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6794 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6795 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6796 22, 23, 24, 25, 26, 27, 28, 29, 30,
6797 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6798 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6799 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6800 22, 23, 24, 25, 26, 27, 28, 29, 30,
6801 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6802 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6803 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6804 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6805 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6806 22, 23, 24, 25, 26, 27, 28, 29, 30,
6807 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6808 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6809 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6810 22, 23, 24, 25, 26, 27, 28, 29, 30,
6811 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6812 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6813
6814static const char kMonthInYear[] = {
6815 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6816 0, 0, 0, 0, 0, 0,
6817 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6818 1, 1, 1,
6819 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6820 2, 2, 2, 2, 2, 2,
6821 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6822 3, 3, 3, 3, 3,
6823 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6824 4, 4, 4, 4, 4, 4,
6825 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6826 5, 5, 5, 5, 5,
6827 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6828 6, 6, 6, 6, 6, 6,
6829 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6830 7, 7, 7, 7, 7, 7,
6831 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6832 8, 8, 8, 8, 8,
6833 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6834 9, 9, 9, 9, 9, 9,
6835 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6836 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6837 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6838 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6839
6840 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6841 0, 0, 0, 0, 0, 0,
6842 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6843 1, 1, 1,
6844 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6845 2, 2, 2, 2, 2, 2,
6846 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6847 3, 3, 3, 3, 3,
6848 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6849 4, 4, 4, 4, 4, 4,
6850 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6851 5, 5, 5, 5, 5,
6852 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6853 6, 6, 6, 6, 6, 6,
6854 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6855 7, 7, 7, 7, 7, 7,
6856 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6857 8, 8, 8, 8, 8,
6858 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6859 9, 9, 9, 9, 9, 9,
6860 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6861 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6862 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6863 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6864
6865 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6866 0, 0, 0, 0, 0, 0,
6867 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6868 1, 1, 1, 1,
6869 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6870 2, 2, 2, 2, 2, 2,
6871 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6872 3, 3, 3, 3, 3,
6873 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6874 4, 4, 4, 4, 4, 4,
6875 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6876 5, 5, 5, 5, 5,
6877 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6878 6, 6, 6, 6, 6, 6,
6879 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6880 7, 7, 7, 7, 7, 7,
6881 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6882 8, 8, 8, 8, 8,
6883 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6884 9, 9, 9, 9, 9, 9,
6885 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6886 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6887 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6888 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6889
6890 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6891 0, 0, 0, 0, 0, 0,
6892 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6893 1, 1, 1,
6894 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6895 2, 2, 2, 2, 2, 2,
6896 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6897 3, 3, 3, 3, 3,
6898 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6899 4, 4, 4, 4, 4, 4,
6900 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6901 5, 5, 5, 5, 5,
6902 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6903 6, 6, 6, 6, 6, 6,
6904 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6905 7, 7, 7, 7, 7, 7,
6906 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6907 8, 8, 8, 8, 8,
6908 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6909 9, 9, 9, 9, 9, 9,
6910 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6911 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6912 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6913 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6914
6915
6916// This function works for dates from 1970 to 2099.
6917static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006918 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006919#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006920 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006921#endif
6922
6923 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6924 date %= kDaysIn4Years;
6925
6926 month = kMonthInYear[date];
6927 day = kDayInYear[date];
6928
6929 ASSERT(MakeDay(year, month, day) == save_date);
6930}
6931
6932
6933static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006934 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006935#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006936 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006937#endif
6938
6939 date += kDaysOffset;
6940 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6941 date %= kDaysIn400Years;
6942
6943 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6944
6945 date--;
6946 int yd1 = date / kDaysIn100Years;
6947 date %= kDaysIn100Years;
6948 year += 100 * yd1;
6949
6950 date++;
6951 int yd2 = date / kDaysIn4Years;
6952 date %= kDaysIn4Years;
6953 year += 4 * yd2;
6954
6955 date--;
6956 int yd3 = date / 365;
6957 date %= 365;
6958 year += yd3;
6959
6960 bool is_leap = (!yd1 || yd2) && !yd3;
6961
6962 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006963 ASSERT(is_leap || (date >= 0));
6964 ASSERT((date < 365) || (is_leap && (date < 366)));
6965 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6966 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6967 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006968
6969 if (is_leap) {
6970 day = kDayInYear[2*365 + 1 + date];
6971 month = kMonthInYear[2*365 + 1 + date];
6972 } else {
6973 day = kDayInYear[date];
6974 month = kMonthInYear[date];
6975 }
6976
6977 ASSERT(MakeDay(year, month, day) == save_date);
6978}
6979
6980
6981static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006982 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006983 if (date >= 0 && date < 32 * kDaysIn4Years) {
6984 DateYMDFromTimeAfter1970(date, year, month, day);
6985 } else {
6986 DateYMDFromTimeSlow(date, year, month, day);
6987 }
6988}
6989
6990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006991RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006992 NoHandleAllocation ha;
6993 ASSERT(args.length() == 2);
6994
6995 CONVERT_DOUBLE_CHECKED(t, args[0]);
6996 CONVERT_CHECKED(JSArray, res_array, args[1]);
6997
6998 int year, month, day;
6999 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007001 RUNTIME_ASSERT(res_array->elements()->map() ==
7002 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007003 FixedArray* elms = FixedArray::cast(res_array->elements());
7004 RUNTIME_ASSERT(elms->length() == 3);
7005
7006 elms->set(0, Smi::FromInt(year));
7007 elms->set(1, Smi::FromInt(month));
7008 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007011}
7012
7013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 3);
7017
7018 JSFunction* callee = JSFunction::cast(args[0]);
7019 Object** parameters = reinterpret_cast<Object**>(args[1]);
7020 const int length = Smi::cast(args[2])->value();
7021
lrn@chromium.org303ada72010-10-27 09:33:13 +00007022 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007023 { MaybeObject* maybe_result =
7024 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007025 if (!maybe_result->ToObject(&result)) return maybe_result;
7026 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007027 // Allocate the elements if needed.
7028 if (length > 0) {
7029 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007030 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007032 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7033 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007034
7035 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007036 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007038 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007039
7040 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007041 for (int i = 0; i < length; i++) {
7042 array->set(i, *--parameters, mode);
7043 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007044 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007045 }
7046 return result;
7047}
7048
7049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007050RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007052 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007053 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007054 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007055 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007057 // Allocate global closures in old space and allocate local closures
7058 // in new space. Additionally pretenure closures that are assigned
7059 // directly to properties.
7060 pretenure = pretenure || (context->global_context() == *context);
7061 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7064 context,
7065 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 return *result;
7067}
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069
7070static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7071 int* total_argc) {
7072 // Find frame containing arguments passed to the caller.
7073 JavaScriptFrameIterator it;
7074 JavaScriptFrame* frame = it.frame();
7075 List<JSFunction*> functions(2);
7076 frame->GetFunctions(&functions);
7077 if (functions.length() > 1) {
7078 int inlined_frame_index = functions.length() - 1;
7079 JSFunction* inlined_function = functions[inlined_frame_index];
7080 int args_count = inlined_function->shared()->formal_parameter_count();
7081 ScopedVector<SlotRef> args_slots(args_count);
7082 SlotRef::ComputeSlotMappingForArguments(frame,
7083 inlined_frame_index,
7084 &args_slots);
7085
7086 *total_argc = bound_argc + args_count;
7087 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7088 for (int i = 0; i < args_count; i++) {
7089 Handle<Object> val = args_slots[i].GetValue();
7090 param_data[bound_argc + i] = val.location();
7091 }
7092 return param_data;
7093 } else {
7094 it.AdvanceToArgumentsFrame();
7095 frame = it.frame();
7096 int args_count = frame->ComputeParametersCount();
7097
7098 *total_argc = bound_argc + args_count;
7099 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7100 for (int i = 0; i < args_count; i++) {
7101 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7102 param_data[bound_argc + i] = val.location();
7103 }
7104 return param_data;
7105 }
7106}
7107
7108
7109RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007110 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007111 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007112 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007113 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007114
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007115 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007117 int bound_argc = 0;
7118 if (!args[1]->IsNull()) {
7119 CONVERT_ARG_CHECKED(JSArray, params, 1);
7120 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007122 bound_argc = Smi::cast(params->length())->value();
7123 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007125 int total_argc = 0;
7126 SmartPointer<Object**> param_data =
7127 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007128 for (int i = 0; i < bound_argc; i++) {
7129 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007130 param_data[i] = val.location();
7131 }
7132
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007133 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007134 Handle<Object> result =
7135 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007136 if (exception) {
7137 return Failure::Exception();
7138 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007139
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007140 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007141 return *result;
7142}
7143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145static void TrySettingInlineConstructStub(Isolate* isolate,
7146 Handle<JSFunction> function) {
7147 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007148 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007150 }
7151 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007152 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007153 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007154 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007155 function->shared()->set_construct_stub(
7156 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007157 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007158 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007159}
7160
7161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007162RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164 ASSERT(args.length() == 1);
7165
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007166 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007168 // If the constructor isn't a proper function we throw a type error.
7169 if (!constructor->IsJSFunction()) {
7170 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7171 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 isolate->factory()->NewTypeError("not_constructor", arguments);
7173 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007174 }
7175
7176 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007177
7178 // If function should not have prototype, construction is not allowed. In this
7179 // case generated code bailouts here, since function has no initial_map.
7180 if (!function->should_have_prototype()) {
7181 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7182 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183 isolate->factory()->NewTypeError("not_constructor", arguments);
7184 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007185 }
7186
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007187#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007189 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 if (debug->StepInActive()) {
7191 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007192 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007193#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007195 if (function->has_initial_map()) {
7196 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197 // The 'Function' function ignores the receiver object when
7198 // called using 'new' and creates a new JSFunction object that
7199 // is returned. The receiver object is only used for error
7200 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007202 // allocate JSFunctions since it does not properly initialize
7203 // the shared part of the function. Since the receiver is
7204 // ignored anyway, we use the global object as the receiver
7205 // instead of a new JSFunction object. This way, errors are
7206 // reported the same way whether or not 'Function' is called
7207 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007210 }
7211
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007212 // The function should be compiled for the optimization hints to be
7213 // available. We cannot use EnsureCompiled because that forces a
7214 // compilation through the shared function info which makes it
7215 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007217 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007218
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007219 if (!function->has_initial_map() &&
7220 shared->IsInobjectSlackTrackingInProgress()) {
7221 // The tracking is already in progress for another function. We can only
7222 // track one initial_map at a time, so we force the completion before the
7223 // function is called as a constructor for the first time.
7224 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007225 }
7226
7227 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7229 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007230 // Delay setting the stub if inobject slack tracking is in progress.
7231 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007232 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007233 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007235 isolate->counters()->constructed_objects()->Increment();
7236 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007237
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007238 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239}
7240
7241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007242RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007243 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007244 ASSERT(args.length() == 1);
7245
7246 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7247 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007250 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007251}
7252
7253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007254RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007255 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007256 ASSERT(args.length() == 1);
7257
7258 Handle<JSFunction> function = args.at<JSFunction>(0);
7259#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007260 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007262 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 PrintF("]\n");
7264 }
7265#endif
7266
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007267 // Compile the target function. Here we compile using CompileLazyInLoop in
7268 // order to get the optimized version. This helps code like delta-blue
7269 // that calls performance-critical routines through constructors. A
7270 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7271 // direct call. Since the in-loop tracking takes place through CallICs
7272 // this means that things called through constructors are never known to
7273 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007275 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 return Failure::Exception();
7277 }
7278
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007279 // All done. Return the compiled code.
7280 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281 return function->code();
7282}
7283
7284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007285RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007287 ASSERT(args.length() == 1);
7288 Handle<JSFunction> function = args.at<JSFunction>(0);
7289 // If the function is not optimizable or debugger is active continue using the
7290 // code from the full compiler.
7291 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007293 if (FLAG_trace_opt) {
7294 PrintF("[failed to optimize ");
7295 function->PrintName();
7296 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7297 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007299 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007300 function->ReplaceCode(function->shared()->code());
7301 return function->code();
7302 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007303 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007304 return function->code();
7305 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007306 if (FLAG_trace_opt) {
7307 PrintF("[failed to optimize ");
7308 function->PrintName();
7309 PrintF(": optimized compilation failed]\n");
7310 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007311 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007312 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007313}
7314
7315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007316RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007318 ASSERT(args.length() == 1);
7319 RUNTIME_ASSERT(args[0]->IsSmi());
7320 Deoptimizer::BailoutType type =
7321 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7323 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007324 int frames = deoptimizer->output_count();
7325
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007326 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007327 JavaScriptFrame* frame = NULL;
7328 for (int i = 0; i < frames; i++) {
7329 if (i != 0) it.Advance();
7330 frame = it.frame();
7331 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7332 }
7333 delete deoptimizer;
7334
7335 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007337 Handle<Object> arguments;
7338 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007340 if (arguments.is_null()) {
7341 // FunctionGetArguments can't throw an exception, so cast away the
7342 // doubt with an assert.
7343 arguments = Handle<Object>(
7344 Accessors::FunctionGetArguments(*function,
7345 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 ASSERT(*arguments != isolate->heap()->null_value());
7347 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007348 }
7349 frame->SetExpression(i, *arguments);
7350 }
7351 }
7352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007354 if (type == Deoptimizer::EAGER) {
7355 RUNTIME_ASSERT(function->IsOptimized());
7356 } else {
7357 RUNTIME_ASSERT(!function->IsOptimized());
7358 }
7359
7360 // Avoid doing too much work when running with --always-opt and keep
7361 // the optimized code around.
7362 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007364 }
7365
7366 // Count the number of optimized activations of the function.
7367 int activations = 0;
7368 while (!it.done()) {
7369 JavaScriptFrame* frame = it.frame();
7370 if (frame->is_optimized() && frame->function() == *function) {
7371 activations++;
7372 }
7373 it.Advance();
7374 }
7375
7376 // TODO(kasperl): For now, we cannot support removing the optimized
7377 // code when we have recursive invocations of the same function.
7378 if (activations == 0) {
7379 if (FLAG_trace_deopt) {
7380 PrintF("[removing optimized code for: ");
7381 function->PrintName();
7382 PrintF("]\n");
7383 }
7384 function->ReplaceCode(function->shared()->code());
7385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007387}
7388
7389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007392 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007394}
7395
7396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007397RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007399 ASSERT(args.length() == 1);
7400 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007402
7403 Deoptimizer::DeoptimizeFunction(*function);
7404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007405 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007406}
7407
7408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007409RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007411 ASSERT(args.length() == 1);
7412 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7413
7414 // We're not prepared to handle a function with arguments object.
7415 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7416
7417 // We have hit a back edge in an unoptimized frame for a function that was
7418 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007420 // Keep track of whether we've succeeded in optimizing.
7421 bool succeeded = unoptimized->optimizable();
7422 if (succeeded) {
7423 // If we are trying to do OSR when there are already optimized
7424 // activations of the function, it means (a) the function is directly or
7425 // indirectly recursive and (b) an optimized invocation has been
7426 // deoptimized so that we are currently in an unoptimized activation.
7427 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007428 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007429 while (succeeded && !it.done()) {
7430 JavaScriptFrame* frame = it.frame();
7431 succeeded = !frame->is_optimized() || frame->function() != *function;
7432 it.Advance();
7433 }
7434 }
7435
7436 int ast_id = AstNode::kNoNumber;
7437 if (succeeded) {
7438 // The top JS function is this one, the PC is somewhere in the
7439 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007440 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007441 JavaScriptFrame* frame = it.frame();
7442 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007443 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007444 ASSERT(unoptimized->contains(frame->pc()));
7445
7446 // Use linear search of the unoptimized code's stack check table to find
7447 // the AST id matching the PC.
7448 Address start = unoptimized->instruction_start();
7449 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007450 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007451 uint32_t table_length = Memory::uint32_at(table_cursor);
7452 table_cursor += kIntSize;
7453 for (unsigned i = 0; i < table_length; ++i) {
7454 // Table entries are (AST id, pc offset) pairs.
7455 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7456 if (pc_offset == target_pc_offset) {
7457 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7458 break;
7459 }
7460 table_cursor += 2 * kIntSize;
7461 }
7462 ASSERT(ast_id != AstNode::kNoNumber);
7463 if (FLAG_trace_osr) {
7464 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7465 function->PrintName();
7466 PrintF("]\n");
7467 }
7468
7469 // Try to compile the optimized code. A true return value from
7470 // CompileOptimized means that compilation succeeded, not necessarily
7471 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007472 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7473 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007474 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7475 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007476 if (data->OsrPcOffset()->value() >= 0) {
7477 if (FLAG_trace_osr) {
7478 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007479 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007480 }
7481 ASSERT(data->OsrAstId()->value() == ast_id);
7482 } else {
7483 // We may never generate the desired OSR entry if we emit an
7484 // early deoptimize.
7485 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007487 } else {
7488 succeeded = false;
7489 }
7490 }
7491
7492 // Revert to the original stack checks in the original unoptimized code.
7493 if (FLAG_trace_osr) {
7494 PrintF("[restoring original stack checks in ");
7495 function->PrintName();
7496 PrintF("]\n");
7497 }
7498 StackCheckStub check_stub;
7499 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007500 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007501 Deoptimizer::RevertStackCheckCode(*unoptimized,
7502 *check_code,
7503 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007504
7505 // Allow OSR only at nesting level zero again.
7506 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7507
7508 // If the optimization attempt succeeded, return the AST id tagged as a
7509 // smi. This tells the builtin that we need to translate the unoptimized
7510 // frame to an optimized one.
7511 if (succeeded) {
7512 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7513 return Smi::FromInt(ast_id);
7514 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007515 if (function->IsMarkedForLazyRecompilation()) {
7516 function->ReplaceCode(function->shared()->code());
7517 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007518 return Smi::FromInt(-1);
7519 }
7520}
7521
7522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007523RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525 ASSERT(args.length() == 1);
7526 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7527 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7528}
7529
7530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007532 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007533 ASSERT(args.length() == 1);
7534 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7535 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7536}
7537
7538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007539RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007540 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007541 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542
kasper.lund7276f142008-07-30 08:49:36 +00007543 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007544 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007545 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007546 { MaybeObject* maybe_result =
7547 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007548 if (!maybe_result->ToObject(&result)) return maybe_result;
7549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007550
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007551 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552
kasper.lund7276f142008-07-30 08:49:36 +00007553 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007554}
7555
lrn@chromium.org303ada72010-10-27 09:33:13 +00007556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7558 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007559 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007561 Object* js_object = object;
7562 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007563 MaybeObject* maybe_js_object = js_object->ToObject();
7564 if (!maybe_js_object->ToObject(&js_object)) {
7565 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7566 return maybe_js_object;
7567 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007568 HandleScope scope(isolate);
7569 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007571 isolate->factory()->NewTypeError("with_expression",
7572 HandleVector(&handle, 1));
7573 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007574 }
7575 }
7576
lrn@chromium.org303ada72010-10-27 09:33:13 +00007577 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007578 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7579 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007580 if (!maybe_result->ToObject(&result)) return maybe_result;
7581 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007582
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007583 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007584 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585
kasper.lund7276f142008-07-30 08:49:36 +00007586 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007587}
7588
7589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007590RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007591 NoHandleAllocation ha;
7592 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007593 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007594}
7595
7596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007597RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007598 NoHandleAllocation ha;
7599 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007600 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007601}
7602
7603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007604RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007605 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007606 ASSERT(args.length() == 2);
7607
7608 CONVERT_ARG_CHECKED(Context, context, 0);
7609 CONVERT_ARG_CHECKED(String, name, 1);
7610
7611 int index;
7612 PropertyAttributes attributes;
7613 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007614 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007615
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007616 // If the slot was not found the result is true.
7617 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619 }
7620
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007621 // If the slot was found in a context, it should be DONT_DELETE.
7622 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007623 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007624 }
7625
7626 // The slot was found in a JSObject, either a context extension object,
7627 // the global object, or an arguments object. Try to delete it
7628 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7629 // which allows deleting all parameters in functions that mention
7630 // 'arguments', we do this even for the case of slots found on an
7631 // arguments object. The slot was found on an arguments object if the
7632 // index is non-negative.
7633 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7634 if (index >= 0) {
7635 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7636 } else {
7637 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639}
7640
7641
ager@chromium.orga1645e22009-09-09 19:27:10 +00007642// A mechanism to return a pair of Object pointers in registers (if possible).
7643// How this is achieved is calling convention-dependent.
7644// All currently supported x86 compiles uses calling conventions that are cdecl
7645// variants where a 64-bit value is returned in two 32-bit registers
7646// (edx:eax on ia32, r1:r0 on ARM).
7647// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7648// In Win64 calling convention, a struct of two pointers is returned in memory,
7649// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007650#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007651struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007652 MaybeObject* x;
7653 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007654};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007655
lrn@chromium.org303ada72010-10-27 09:33:13 +00007656static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007657 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007658 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7659 // In Win64 they are assigned to a hidden first argument.
7660 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007661}
7662#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007663typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007664static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007665 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007666 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007667}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007668#endif
7669
7670
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007671static inline MaybeObject* Unhole(Heap* heap,
7672 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007673 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007674 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7675 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007676 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007677}
7678
7679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7681 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007682 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007683 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007684 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007685 JSFunction* context_extension_function =
7686 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007687 // If the holder isn't a context extension object, we just return it
7688 // as the receiver. This allows arguments objects to be used as
7689 // receivers, but only if they are put in the context scope chain
7690 // explicitly via a with-statement.
7691 Object* constructor = holder->map()->constructor();
7692 if (constructor != context_extension_function) return holder;
7693 // Fall back to using the global object as the receiver if the
7694 // property turns out to be a local variable allocated in a context
7695 // extension object - introduced via eval.
7696 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007697}
7698
7699
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700static ObjectPair LoadContextSlotHelper(Arguments args,
7701 Isolate* isolate,
7702 bool throw_error) {
7703 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007704 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007705
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007706 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007710 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711
7712 int index;
7713 PropertyAttributes attributes;
7714 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007715 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007717 // If the index is non-negative, the slot has been found in a local
7718 // variable or a parameter. Read it from the context object or the
7719 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007720 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007721 // If the "property" we were looking for is a local variable or an
7722 // argument in a context, the receiver is the global object; see
7723 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007724 JSObject* receiver =
7725 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007726 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007727 ? Context::cast(*holder)->get(index)
7728 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007729 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730 }
7731
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007732 // If the holder is found, we read the property from it.
7733 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007734 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007735 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007736 JSObject* receiver;
7737 if (object->IsGlobalObject()) {
7738 receiver = GlobalObject::cast(object)->global_receiver();
7739 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007740 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007741 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007742 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007743 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007744 // No need to unhole the value here. This is taken care of by the
7745 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007746 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007747 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 }
7749
7750 if (throw_error) {
7751 // The property doesn't exist - throw exception.
7752 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 isolate->factory()->NewReferenceError("not_defined",
7754 HandleVector(&name, 1));
7755 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007756 } else {
7757 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 return MakePair(isolate->heap()->undefined_value(),
7759 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760 }
7761}
7762
7763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007765 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766}
7767
7768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007769RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007770 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007771}
7772
7773
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007774RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007775 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007776 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007778 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007780 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007781 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7782 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7783 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007784 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007785
7786 int index;
7787 PropertyAttributes attributes;
7788 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007789 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790
7791 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007792 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007793 // Ignore if read_only variable.
7794 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007795 // Context is a fixed array and set cannot fail.
7796 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007797 } else if (strict_mode == kStrictMode) {
7798 // Setting read only property in strict mode.
7799 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007800 isolate->factory()->NewTypeError("strict_cannot_assign",
7801 HandleVector(&name, 1));
7802 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803 }
7804 } else {
7805 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007806 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007807 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007808 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007809 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007810 return Failure::Exception();
7811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812 }
7813 return *value;
7814 }
7815
7816 // Slow case: The property is not in a FixedArray context.
7817 // It is either in an JSObject extension context or it was not found.
7818 Handle<JSObject> context_ext;
7819
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007820 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007822 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823 } else {
7824 // The property was not found. It needs to be stored in the global context.
7825 ASSERT(attributes == ABSENT);
7826 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007827 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007828 }
7829
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007830 // Set the property, but ignore if read_only variable on the context
7831 // extension object itself.
7832 if ((attributes & READ_ONLY) == 0 ||
7833 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007834 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007835 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007836 SetProperty(context_ext, name, value, NONE, strict_mode));
7837 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007838 // Setting read only property in strict mode.
7839 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840 isolate->factory()->NewTypeError(
7841 "strict_cannot_assign", HandleVector(&name, 1));
7842 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007843 }
7844 return *value;
7845}
7846
7847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007848RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007849 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007850 ASSERT(args.length() == 1);
7851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853}
7854
7855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007856RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858 ASSERT(args.length() == 1);
7859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861}
7862
7863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007864RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007865 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007867}
7868
7869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007870RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007872 ASSERT(args.length() == 1);
7873
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007874 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 isolate->factory()->NewReferenceError("not_defined",
7877 HandleVector(&name, 1));
7878 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007879}
7880
7881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007882RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007883 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884
7885 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007886 if (isolate->stack_guard()->IsStackOverflow()) {
7887 NoHandleAllocation na;
7888 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007890
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007891 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892}
7893
7894
7895// NOTE: These PrintXXX functions are defined for all builds (not just
7896// DEBUG builds) because we may want to be able to trace function
7897// calls in all modes.
7898static void PrintString(String* str) {
7899 // not uncommon to have empty strings
7900 if (str->length() > 0) {
7901 SmartPointer<char> s =
7902 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7903 PrintF("%s", *s);
7904 }
7905}
7906
7907
7908static void PrintObject(Object* obj) {
7909 if (obj->IsSmi()) {
7910 PrintF("%d", Smi::cast(obj)->value());
7911 } else if (obj->IsString() || obj->IsSymbol()) {
7912 PrintString(String::cast(obj));
7913 } else if (obj->IsNumber()) {
7914 PrintF("%g", obj->Number());
7915 } else if (obj->IsFailure()) {
7916 PrintF("<failure>");
7917 } else if (obj->IsUndefined()) {
7918 PrintF("<undefined>");
7919 } else if (obj->IsNull()) {
7920 PrintF("<null>");
7921 } else if (obj->IsTrue()) {
7922 PrintF("<true>");
7923 } else if (obj->IsFalse()) {
7924 PrintF("<false>");
7925 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007926 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927 }
7928}
7929
7930
7931static int StackSize() {
7932 int n = 0;
7933 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7934 return n;
7935}
7936
7937
7938static void PrintTransition(Object* result) {
7939 // indentation
7940 { const int nmax = 80;
7941 int n = StackSize();
7942 if (n <= nmax)
7943 PrintF("%4d:%*s", n, n, "");
7944 else
7945 PrintF("%4d:%*s", n, nmax, "...");
7946 }
7947
7948 if (result == NULL) {
7949 // constructor calls
7950 JavaScriptFrameIterator it;
7951 JavaScriptFrame* frame = it.frame();
7952 if (frame->IsConstructor()) PrintF("new ");
7953 // function name
7954 Object* fun = frame->function();
7955 if (fun->IsJSFunction()) {
7956 PrintObject(JSFunction::cast(fun)->shared()->name());
7957 } else {
7958 PrintObject(fun);
7959 }
7960 // function arguments
7961 // (we are intentionally only printing the actually
7962 // supplied parameters, not all parameters required)
7963 PrintF("(this=");
7964 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007965 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 for (int i = 0; i < length; i++) {
7967 PrintF(", ");
7968 PrintObject(frame->GetParameter(i));
7969 }
7970 PrintF(") {\n");
7971
7972 } else {
7973 // function result
7974 PrintF("} -> ");
7975 PrintObject(result);
7976 PrintF("\n");
7977 }
7978}
7979
7980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007981RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007982 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983 NoHandleAllocation ha;
7984 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007985 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986}
7987
7988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007989RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007990 NoHandleAllocation ha;
7991 PrintTransition(args[0]);
7992 return args[0]; // return TOS
7993}
7994
7995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007996RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007997 NoHandleAllocation ha;
7998 ASSERT(args.length() == 1);
7999
8000#ifdef DEBUG
8001 if (args[0]->IsString()) {
8002 // If we have a string, assume it's a code "marker"
8003 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008004 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008006 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8007 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008 } else {
8009 PrintF("DebugPrint: ");
8010 }
8011 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008012 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008013 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008014 HeapObject::cast(args[0])->map()->Print();
8015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008016#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008017 // ShortPrint is available in release mode. Print is not.
8018 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008019#endif
8020 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008021 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008022
8023 return args[0]; // return TOS
8024}
8025
8026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008027RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008028 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 isolate->PrintStack();
8031 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032}
8033
8034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008035RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008037 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038
8039 // According to ECMA-262, section 15.9.1, page 117, the precision of
8040 // the number in a Date object representing a particular instant in
8041 // time is milliseconds. Therefore, we floor the result of getting
8042 // the OS time.
8043 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008044 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008045}
8046
8047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008048RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008050 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008052 CONVERT_ARG_CHECKED(String, str, 0);
8053 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008055 CONVERT_ARG_CHECKED(JSArray, output, 1);
8056 RUNTIME_ASSERT(output->HasFastElements());
8057
8058 AssertNoAllocation no_allocation;
8059
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008060 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008061 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8062 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008063 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008064 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008066 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008067 result = DateParser::Parse(str->ToUC16Vector(), output_array);
8068 }
8069
8070 if (result) {
8071 return *output;
8072 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008073 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008074 }
8075}
8076
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008079 NoHandleAllocation ha;
8080 ASSERT(args.length() == 1);
8081
8082 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008083 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008084 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008085}
8086
8087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008088RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008089 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008090 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008092 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008093}
8094
8095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008096RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 NoHandleAllocation ha;
8098 ASSERT(args.length() == 1);
8099
8100 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008101 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102}
8103
8104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008105RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008106 ASSERT(args.length() == 1);
8107 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008109 return JSGlobalObject::cast(global)->global_receiver();
8110}
8111
8112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008113RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008114 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008115 ASSERT_EQ(1, args.length());
8116 CONVERT_ARG_CHECKED(String, source, 0);
8117
8118 Handle<Object> result = JsonParser::Parse(source);
8119 if (result.is_null()) {
8120 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008122 return Failure::Exception();
8123 }
8124 return *result;
8125}
8126
8127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008128RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008129 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008130 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008131 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008132
ager@chromium.org381abbb2009-02-25 13:23:22 +00008133 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008134 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008135 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8136 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008137 true,
8138 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008139 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008140 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008141 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8142 context,
8143 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008144 return *fun;
8145}
8146
8147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008148static ObjectPair CompileGlobalEval(Isolate* isolate,
8149 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008150 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008151 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008152 // Deal with a normal eval call with a string argument. Compile it
8153 // and return the compiled function bound in the local context.
8154 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8155 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156 Handle<Context>(isolate->context()),
8157 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008158 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008159 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 Handle<JSFunction> compiled =
8161 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8162 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008163 return MakePair(*compiled, *receiver);
8164}
8165
8166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008167RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008168 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008170 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008171 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008172 Handle<Object> receiver; // Will be overwritten.
8173
8174 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008175 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008176#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008177 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008178 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008179 StackFrameLocator locator;
8180 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008181 ASSERT(Context::cast(frame->context()) == *context);
8182#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008183
8184 // Find where the 'eval' symbol is bound. It is unaliased only if
8185 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008186 int index = -1;
8187 PropertyAttributes attributes = ABSENT;
8188 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008189 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8190 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008191 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008192 // Stop search when eval is found or when the global context is
8193 // reached.
8194 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008195 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008196 context = Handle<Context>(Context::cast(context->closure()->context()),
8197 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008198 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008200 }
8201 }
8202
iposva@chromium.org245aa852009-02-10 00:49:54 +00008203 // If eval could not be resolved, it has been deleted and we need to
8204 // throw a reference error.
8205 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008207 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 isolate->factory()->NewReferenceError("not_defined",
8209 HandleVector(&name, 1));
8210 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008211 }
8212
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008213 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008214 // 'eval' is not bound in the global context. Just call the function
8215 // with the given arguments. This is not necessarily the global eval.
8216 if (receiver->IsContext()) {
8217 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008219 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 receiver = Handle<JSObject>(
8221 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008223 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008224 }
8225
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008226 // 'eval' is bound in the global context, but it may have been overwritten.
8227 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008229 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 return MakePair(*callee,
8231 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008232 }
8233
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008234 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008235 return CompileGlobalEval(isolate,
8236 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008237 args.at<Object>(2),
8238 static_cast<StrictModeFlag>(
8239 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008240}
8241
8242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008243RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008244 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008247 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008248
8249 // 'eval' is bound in the global context, but it may have been overwritten.
8250 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008252 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 return MakePair(*callee,
8254 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008255 }
8256
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008257 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008258 return CompileGlobalEval(isolate,
8259 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008260 args.at<Object>(2),
8261 static_cast<StrictModeFlag>(
8262 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008263}
8264
8265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008266RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 // This utility adjusts the property attributes for newly created Function
8268 // object ("new Function(...)") by changing the map.
8269 // All it does is changing the prototype property to enumerable
8270 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272 ASSERT(args.length() == 1);
8273 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274
8275 Handle<Map> map = func->shared()->strict_mode()
8276 ? isolate->strict_mode_function_instance_map()
8277 : isolate->function_instance_map();
8278
8279 ASSERT(func->map()->instance_type() == map->instance_type());
8280 ASSERT(func->map()->instance_size() == map->instance_size());
8281 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282 return *func;
8283}
8284
8285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008286RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008287 // Allocate a block of memory in NewSpace (filled with a filler).
8288 // Use as fallback for allocation in generated code when NewSpace
8289 // is full.
8290 ASSERT(args.length() == 1);
8291 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8292 int size = size_smi->value();
8293 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8294 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 Heap* heap = isolate->heap();
8296 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008297 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008298 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008301 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008302 }
8303 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008304 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008305}
8306
8307
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008308// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008309// array. Returns true if the element was pushed on the stack and
8310// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008311RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008312 ASSERT(args.length() == 2);
8313 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008314 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008315 RUNTIME_ASSERT(array->HasFastElements());
8316 int length = Smi::cast(array->length())->value();
8317 FixedArray* elements = FixedArray::cast(array->elements());
8318 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008319 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008320 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008321 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008322 // Strict not needed. Used for cycle detection in Array join implementation.
8323 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8324 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008325 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8326 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008327 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008328}
8329
8330
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008331/**
8332 * A simple visitor visits every element of Array's.
8333 * The backend storage can be a fixed array for fast elements case,
8334 * or a dictionary for sparse array. Since Dictionary is a subtype
8335 * of FixedArray, the class can be used by both fast and slow cases.
8336 * The second parameter of the constructor, fast_elements, specifies
8337 * whether the storage is a FixedArray or Dictionary.
8338 *
8339 * An index limit is used to deal with the situation that a result array
8340 * length overflows 32-bit non-negative integer.
8341 */
8342class ArrayConcatVisitor {
8343 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 ArrayConcatVisitor(Isolate* isolate,
8345 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008346 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008347 isolate_(isolate),
8348 storage_(Handle<FixedArray>::cast(
8349 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008350 index_offset_(0u),
8351 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008352
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008353 ~ArrayConcatVisitor() {
8354 clear_storage();
8355 }
8356
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008357 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008358 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008359 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008360
8361 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008362 if (index < static_cast<uint32_t>(storage_->length())) {
8363 storage_->set(index, *elm);
8364 return;
8365 }
8366 // Our initial estimate of length was foiled, possibly by
8367 // getters on the arrays increasing the length of later arrays
8368 // during iteration.
8369 // This shouldn't happen in anything but pathological cases.
8370 SetDictionaryMode(index);
8371 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008372 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008373 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008374 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008375 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008377 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008378 // Dictionary needed to grow.
8379 clear_storage();
8380 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008381 }
8382}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008383
8384 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008385 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8386 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008387 } else {
8388 index_offset_ += delta;
8389 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008390 }
8391
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008392 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008394 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008395 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008396 Handle<Map> map;
8397 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008398 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008399 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008401 }
8402 array->set_map(*map);
8403 array->set_length(*length);
8404 array->set_elements(*storage_);
8405 return array;
8406 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008407
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008408 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008409 // Convert storage to dictionary mode.
8410 void SetDictionaryMode(uint32_t index) {
8411 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008412 Handle<FixedArray> current_storage(*storage_);
8413 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008415 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8416 for (uint32_t i = 0; i < current_length; i++) {
8417 HandleScope loop_scope;
8418 Handle<Object> element(current_storage->get(i));
8419 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008420 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008421 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008422 if (!new_storage.is_identical_to(slow_storage)) {
8423 slow_storage = loop_scope.CloseAndEscape(new_storage);
8424 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008425 }
8426 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008427 clear_storage();
8428 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008429 fast_elements_ = false;
8430 }
8431
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008432 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 isolate_->global_handles()->Destroy(
8434 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008435 }
8436
8437 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008438 storage_ = Handle<FixedArray>::cast(
8439 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008440 }
8441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008442 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008443 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008444 // Index after last seen index. Always less than or equal to
8445 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008446 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008447 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008448};
8449
8450
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008451static uint32_t EstimateElementCount(Handle<JSArray> array) {
8452 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8453 int element_count = 0;
8454 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008455 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008456 // Fast elements can't have lengths that are not representable by
8457 // a 32-bit signed integer.
8458 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8459 int fast_length = static_cast<int>(length);
8460 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8461 for (int i = 0; i < fast_length; i++) {
8462 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008463 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008464 break;
8465 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008466 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008467 Handle<NumberDictionary> dictionary(
8468 NumberDictionary::cast(array->elements()));
8469 int capacity = dictionary->Capacity();
8470 for (int i = 0; i < capacity; i++) {
8471 Handle<Object> key(dictionary->KeyAt(i));
8472 if (dictionary->IsKey(*key)) {
8473 element_count++;
8474 }
8475 }
8476 break;
8477 }
8478 default:
8479 // External arrays are always dense.
8480 return length;
8481 }
8482 // As an estimate, we assume that the prototype doesn't contain any
8483 // inherited elements.
8484 return element_count;
8485}
8486
8487
8488
8489template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490static void IterateExternalArrayElements(Isolate* isolate,
8491 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008492 bool elements_are_ints,
8493 bool elements_are_guaranteed_smis,
8494 ArrayConcatVisitor* visitor) {
8495 Handle<ExternalArrayClass> array(
8496 ExternalArrayClass::cast(receiver->elements()));
8497 uint32_t len = static_cast<uint32_t>(array->length());
8498
8499 ASSERT(visitor != NULL);
8500 if (elements_are_ints) {
8501 if (elements_are_guaranteed_smis) {
8502 for (uint32_t j = 0; j < len; j++) {
8503 HandleScope loop_scope;
8504 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8505 visitor->visit(j, e);
8506 }
8507 } else {
8508 for (uint32_t j = 0; j < len; j++) {
8509 HandleScope loop_scope;
8510 int64_t val = static_cast<int64_t>(array->get(j));
8511 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8512 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8513 visitor->visit(j, e);
8514 } else {
8515 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008516 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008517 visitor->visit(j, e);
8518 }
8519 }
8520 }
8521 } else {
8522 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008523 HandleScope loop_scope(isolate);
8524 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008525 visitor->visit(j, e);
8526 }
8527 }
8528}
8529
8530
8531// Used for sorting indices in a List<uint32_t>.
8532static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8533 uint32_t a = *ap;
8534 uint32_t b = *bp;
8535 return (a == b) ? 0 : (a < b) ? -1 : 1;
8536}
8537
8538
8539static void CollectElementIndices(Handle<JSObject> object,
8540 uint32_t range,
8541 List<uint32_t>* indices) {
8542 JSObject::ElementsKind kind = object->GetElementsKind();
8543 switch (kind) {
8544 case JSObject::FAST_ELEMENTS: {
8545 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8546 uint32_t length = static_cast<uint32_t>(elements->length());
8547 if (range < length) length = range;
8548 for (uint32_t i = 0; i < length; i++) {
8549 if (!elements->get(i)->IsTheHole()) {
8550 indices->Add(i);
8551 }
8552 }
8553 break;
8554 }
8555 case JSObject::DICTIONARY_ELEMENTS: {
8556 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008557 uint32_t capacity = dict->Capacity();
8558 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008559 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008560 Handle<Object> k(dict->KeyAt(j));
8561 if (dict->IsKey(*k)) {
8562 ASSERT(k->IsNumber());
8563 uint32_t index = static_cast<uint32_t>(k->Number());
8564 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008565 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008566 }
8567 }
8568 }
8569 break;
8570 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008571 default: {
8572 int dense_elements_length;
8573 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008574 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008575 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008576 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008577 break;
8578 }
8579 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8580 dense_elements_length =
8581 ExternalByteArray::cast(object->elements())->length();
8582 break;
8583 }
8584 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8585 dense_elements_length =
8586 ExternalUnsignedByteArray::cast(object->elements())->length();
8587 break;
8588 }
8589 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8590 dense_elements_length =
8591 ExternalShortArray::cast(object->elements())->length();
8592 break;
8593 }
8594 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8595 dense_elements_length =
8596 ExternalUnsignedShortArray::cast(object->elements())->length();
8597 break;
8598 }
8599 case JSObject::EXTERNAL_INT_ELEMENTS: {
8600 dense_elements_length =
8601 ExternalIntArray::cast(object->elements())->length();
8602 break;
8603 }
8604 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8605 dense_elements_length =
8606 ExternalUnsignedIntArray::cast(object->elements())->length();
8607 break;
8608 }
8609 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8610 dense_elements_length =
8611 ExternalFloatArray::cast(object->elements())->length();
8612 break;
8613 }
8614 default:
8615 UNREACHABLE();
8616 dense_elements_length = 0;
8617 break;
8618 }
8619 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8620 if (range <= length) {
8621 length = range;
8622 // We will add all indices, so we might as well clear it first
8623 // and avoid duplicates.
8624 indices->Clear();
8625 }
8626 for (uint32_t i = 0; i < length; i++) {
8627 indices->Add(i);
8628 }
8629 if (length == range) return; // All indices accounted for already.
8630 break;
8631 }
8632 }
8633
8634 Handle<Object> prototype(object->GetPrototype());
8635 if (prototype->IsJSObject()) {
8636 // The prototype will usually have no inherited element indices,
8637 // but we have to check.
8638 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8639 }
8640}
8641
8642
8643/**
8644 * A helper function that visits elements of a JSArray in numerical
8645 * order.
8646 *
8647 * The visitor argument called for each existing element in the array
8648 * with the element index and the element's value.
8649 * Afterwards it increments the base-index of the visitor by the array
8650 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008651 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008652 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008653static bool IterateElements(Isolate* isolate,
8654 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008655 ArrayConcatVisitor* visitor) {
8656 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8657 switch (receiver->GetElementsKind()) {
8658 case JSObject::FAST_ELEMENTS: {
8659 // Run through the elements FixedArray and use HasElement and GetElement
8660 // to check the prototype for missing elements.
8661 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8662 int fast_length = static_cast<int>(length);
8663 ASSERT(fast_length <= elements->length());
8664 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008665 HandleScope loop_scope(isolate);
8666 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008667 if (!element_value->IsTheHole()) {
8668 visitor->visit(j, element_value);
8669 } else if (receiver->HasElement(j)) {
8670 // Call GetElement on receiver, not its prototype, or getters won't
8671 // have the correct receiver.
8672 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008673 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008674 visitor->visit(j, element_value);
8675 }
8676 }
8677 break;
8678 }
8679 case JSObject::DICTIONARY_ELEMENTS: {
8680 Handle<NumberDictionary> dict(receiver->element_dictionary());
8681 List<uint32_t> indices(dict->Capacity() / 2);
8682 // Collect all indices in the object and the prototypes less
8683 // than length. This might introduce duplicates in the indices list.
8684 CollectElementIndices(receiver, length, &indices);
8685 indices.Sort(&compareUInt32);
8686 int j = 0;
8687 int n = indices.length();
8688 while (j < n) {
8689 HandleScope loop_scope;
8690 uint32_t index = indices[j];
8691 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008692 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008693 visitor->visit(index, element);
8694 // Skip to next different index (i.e., omit duplicates).
8695 do {
8696 j++;
8697 } while (j < n && indices[j] == index);
8698 }
8699 break;
8700 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008701 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8702 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8703 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008704 for (uint32_t j = 0; j < length; j++) {
8705 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8706 visitor->visit(j, e);
8707 }
8708 break;
8709 }
8710 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8711 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008712 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008713 break;
8714 }
8715 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8716 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008717 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008718 break;
8719 }
8720 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8721 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008722 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008723 break;
8724 }
8725 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8726 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008727 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008728 break;
8729 }
8730 case JSObject::EXTERNAL_INT_ELEMENTS: {
8731 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008732 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008733 break;
8734 }
8735 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8736 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008737 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008738 break;
8739 }
8740 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8741 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008742 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008743 break;
8744 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008745 default:
8746 UNREACHABLE();
8747 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008748 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008750 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008751}
8752
8753
8754/**
8755 * Array::concat implementation.
8756 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008757 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008758 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008759 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008760RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008761 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008762 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008763
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008764 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8765 int argument_count = static_cast<int>(arguments->length()->Number());
8766 RUNTIME_ASSERT(arguments->HasFastElements());
8767 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008768
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008769 // Pass 1: estimate the length and number of elements of the result.
8770 // The actual length can be larger if any of the arguments have getters
8771 // that mutate other arguments (but will otherwise be precise).
8772 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008773
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 uint32_t estimate_result_length = 0;
8775 uint32_t estimate_nof_elements = 0;
8776 {
8777 for (int i = 0; i < argument_count; i++) {
8778 HandleScope loop_scope;
8779 Handle<Object> obj(elements->get(i));
8780 uint32_t length_estimate;
8781 uint32_t element_estimate;
8782 if (obj->IsJSArray()) {
8783 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8784 length_estimate =
8785 static_cast<uint32_t>(array->length()->Number());
8786 element_estimate =
8787 EstimateElementCount(array);
8788 } else {
8789 length_estimate = 1;
8790 element_estimate = 1;
8791 }
8792 // Avoid overflows by capping at kMaxElementCount.
8793 if (JSObject::kMaxElementCount - estimate_result_length <
8794 length_estimate) {
8795 estimate_result_length = JSObject::kMaxElementCount;
8796 } else {
8797 estimate_result_length += length_estimate;
8798 }
8799 if (JSObject::kMaxElementCount - estimate_nof_elements <
8800 element_estimate) {
8801 estimate_nof_elements = JSObject::kMaxElementCount;
8802 } else {
8803 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008804 }
8805 }
8806 }
8807
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008808 // If estimated number of elements is more than half of length, a
8809 // fixed array (fast case) is more time and space-efficient than a
8810 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008811 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008812
8813 Handle<FixedArray> storage;
8814 if (fast_case) {
8815 // The backing storage array must have non-existing elements to
8816 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008817 storage = isolate->factory()->NewFixedArrayWithHoles(
8818 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008819 } else {
8820 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8821 uint32_t at_least_space_for = estimate_nof_elements +
8822 (estimate_nof_elements >> 2);
8823 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008825 }
8826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008828
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008829 for (int i = 0; i < argument_count; i++) {
8830 Handle<Object> obj(elements->get(i));
8831 if (obj->IsJSArray()) {
8832 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008833 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008834 return Failure::Exception();
8835 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008836 } else {
8837 visitor.visit(0, obj);
8838 visitor.increase_index_offset(1);
8839 }
8840 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008841
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008842 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008843}
8844
8845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846// This will not allocate (flatten the string), but it may run
8847// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008848RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008849 NoHandleAllocation ha;
8850 ASSERT(args.length() == 1);
8851
8852 CONVERT_CHECKED(String, string, args[0]);
8853 StringInputBuffer buffer(string);
8854 while (buffer.has_more()) {
8855 uint16_t character = buffer.GetNext();
8856 PrintF("%c", character);
8857 }
8858 return string;
8859}
8860
ager@chromium.org5ec48922009-05-05 07:25:34 +00008861// Moves all own elements of an object, that are below a limit, to positions
8862// starting at zero. All undefined values are placed after non-undefined values,
8863// and are followed by non-existing element. Does not change the length
8864// property.
8865// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008866RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008867 ASSERT(args.length() == 2);
8868 CONVERT_CHECKED(JSObject, object, args[0]);
8869 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8870 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871}
8872
8873
8874// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008875RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876 ASSERT(args.length() == 2);
8877 CONVERT_CHECKED(JSArray, from, args[0]);
8878 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008879 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008880 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8882 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008883 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008884 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008885 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008886 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008887 Object* new_map;
8888 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008889 to->set_map(Map::cast(new_map));
8890 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008892 Object* obj;
8893 { MaybeObject* maybe_obj = from->ResetElements();
8894 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8895 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008896 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897 return to;
8898}
8899
8900
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008901// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008902RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008903 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008904 CONVERT_CHECKED(JSObject, object, args[0]);
8905 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008907 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008908 } else if (object->IsJSArray()) {
8909 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008911 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 }
8913}
8914
8915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008918
8919 ASSERT_EQ(3, args.length());
8920
ager@chromium.orgac091b72010-05-05 07:34:42 +00008921 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008922 Handle<Object> key1 = args.at<Object>(1);
8923 Handle<Object> key2 = args.at<Object>(2);
8924
8925 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008926 if (!key1->ToArrayIndex(&index1)
8927 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008929 }
8930
ager@chromium.orgac091b72010-05-05 07:34:42 +00008931 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8932 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008934 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008935 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 RETURN_IF_EMPTY_HANDLE(isolate,
8938 SetElement(jsobject, index1, tmp2, kStrictMode));
8939 RETURN_IF_EMPTY_HANDLE(isolate,
8940 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008942 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008943}
8944
8945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008947// might have elements. Can either return keys (positive integers) or
8948// intervals (pair of a negative integer (-start-1) followed by a
8949// positive (length)) or undefined values.
8950// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008951RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008952 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008953 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00008954 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008956 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 // Create an array and get all the keys into it, then remove all the
8958 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008959 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 int keys_length = keys->length();
8961 for (int i = 0; i < keys_length; i++) {
8962 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008963 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008964 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 // Zap invalid keys.
8966 keys->set_undefined(i);
8967 }
8968 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008971 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008974 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008975 uint32_t actual_length =
8976 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008977 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008979 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 }
8983}
8984
8985
8986// DefineAccessor takes an optional final argument which is the
8987// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8988// to the way accessors are implemented, it is set for both the getter
8989// and setter on the first call to DefineAccessor and ignored on
8990// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008991RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008992 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8993 // Compute attributes.
8994 PropertyAttributes attributes = NONE;
8995 if (args.length() == 5) {
8996 CONVERT_CHECKED(Smi, attrs, args[4]);
8997 int value = attrs->value();
8998 // Only attribute bits should be set.
8999 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9000 attributes = static_cast<PropertyAttributes>(value);
9001 }
9002
9003 CONVERT_CHECKED(JSObject, obj, args[0]);
9004 CONVERT_CHECKED(String, name, args[1]);
9005 CONVERT_CHECKED(Smi, flag, args[2]);
9006 CONVERT_CHECKED(JSFunction, fun, args[3]);
9007 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9008}
9009
9010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009011RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 ASSERT(args.length() == 3);
9013 CONVERT_CHECKED(JSObject, obj, args[0]);
9014 CONVERT_CHECKED(String, name, args[1]);
9015 CONVERT_CHECKED(Smi, flag, args[2]);
9016 return obj->LookupAccessor(name, flag->value() == 0);
9017}
9018
9019
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009020#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009021RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009022 ASSERT(args.length() == 0);
9023 return Execution::DebugBreakHelper();
9024}
9025
9026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027// Helper functions for wrapping and unwrapping stack frame ids.
9028static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009029 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030 return Smi::FromInt(id >> 2);
9031}
9032
9033
9034static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9035 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9036}
9037
9038
9039// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009040// args[0]: debug event listener function to set or null or undefined for
9041// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009042// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009043RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009045 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9046 args[0]->IsUndefined() ||
9047 args[0]->IsNull());
9048 Handle<Object> callback = args.at<Object>(0);
9049 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009050 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009052 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053}
9054
9055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009056RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009057 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058 isolate->stack_guard()->DebugBreak();
9059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060}
9061
9062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063static MaybeObject* DebugLookupResultValue(Heap* heap,
9064 Object* receiver,
9065 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009066 LookupResult* result,
9067 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009068 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009070 case NORMAL:
9071 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009072 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009073 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 }
9075 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009076 case FIELD:
9077 value =
9078 JSObject::cast(
9079 result->holder())->FastPropertyAt(result->GetFieldIndex());
9080 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009082 }
9083 return value;
9084 case CONSTANT_FUNCTION:
9085 return result->GetConstantFunction();
9086 case CALLBACKS: {
9087 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009088 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009089 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009090 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009091 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009092 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009093 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 maybe_value = heap->isolate()->pending_exception();
9095 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009096 if (caught_exception != NULL) {
9097 *caught_exception = true;
9098 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009099 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009100 }
9101 return value;
9102 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009103 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009104 }
9105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009107 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009108 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009109 case CONSTANT_TRANSITION:
9110 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009112 default:
9113 UNREACHABLE();
9114 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009115 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117}
9118
9119
ager@chromium.org32912102009-01-16 10:38:43 +00009120// Get debugger related details for an object property.
9121// args[0]: object holding property
9122// args[1]: name of the property
9123//
9124// The array returned contains the following information:
9125// 0: Property value
9126// 1: Property details
9127// 2: Property value is exception
9128// 3: Getter function if defined
9129// 4: Setter function if defined
9130// Items 2-4 are only filled if the property has either a getter or a setter
9131// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009132RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009134
9135 ASSERT(args.length() == 2);
9136
9137 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9138 CONVERT_ARG_CHECKED(String, name, 1);
9139
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009140 // Make sure to set the current context to the context before the debugger was
9141 // entered (if the debugger is entered). The reason for switching context here
9142 // is that for some property lookups (accessors and interceptors) callbacks
9143 // into the embedding application can occour, and the embedding application
9144 // could have the assumption that its own global context is the current
9145 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 SaveContext save(isolate);
9147 if (isolate->debug()->InDebugger()) {
9148 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009149 }
9150
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009151 // Skip the global proxy as it has no properties and always delegates to the
9152 // real global object.
9153 if (obj->IsJSGlobalProxy()) {
9154 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9155 }
9156
9157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 // Check if the name is trivially convertible to an index and get the element
9159 // if so.
9160 uint32_t index;
9161 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009163 Object* element_or_char;
9164 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009166 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9167 return maybe_element_or_char;
9168 }
9169 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009170 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173 }
9174
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009175 // Find the number of objects making up this.
9176 int length = LocalPrototypeChainLength(*obj);
9177
9178 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009179 Handle<JSObject> jsproto = obj;
9180 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009181 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009182 jsproto->LocalLookup(*name, &result);
9183 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009184 // LookupResult is not GC safe as it holds raw object pointers.
9185 // GC can happen later in this code so put the required fields into
9186 // local variables using handles when required for later use.
9187 PropertyType result_type = result.type();
9188 Handle<Object> result_callback_obj;
9189 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009190 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9191 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009192 }
9193 Smi* property_details = result.GetPropertyDetails().AsSmi();
9194 // DebugLookupResultValue can cause GC so details from LookupResult needs
9195 // to be copied to handles before this.
9196 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009197 Object* raw_value;
9198 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 DebugLookupResultValue(isolate->heap(), *obj, *name,
9200 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009201 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009204
9205 // If the callback object is a fixed array then it contains JavaScript
9206 // getter and/or setter.
9207 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9208 result_callback_obj->IsFixedArray();
9209 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009211 details->set(0, *value);
9212 details->set(1, property_details);
9213 if (hasJavaScriptAccessors) {
9214 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 caught_exception ? isolate->heap()->true_value()
9216 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009217 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9218 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9219 }
9220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009221 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009222 }
9223 if (i < length - 1) {
9224 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9225 }
9226 }
9227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009228 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229}
9230
9231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009232RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234
9235 ASSERT(args.length() == 2);
9236
9237 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9238 CONVERT_ARG_CHECKED(String, name, 1);
9239
9240 LookupResult result;
9241 obj->Lookup(*name, &result);
9242 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246}
9247
9248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249// Return the property type calculated from the property details.
9250// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009251RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 ASSERT(args.length() == 1);
9253 CONVERT_CHECKED(Smi, details, args[0]);
9254 PropertyType type = PropertyDetails(details).type();
9255 return Smi::FromInt(static_cast<int>(type));
9256}
9257
9258
9259// Return the property attribute calculated from the property details.
9260// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009261RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262 ASSERT(args.length() == 1);
9263 CONVERT_CHECKED(Smi, details, args[0]);
9264 PropertyAttributes attributes = PropertyDetails(details).attributes();
9265 return Smi::FromInt(static_cast<int>(attributes));
9266}
9267
9268
9269// Return the property insertion index calculated from the property details.
9270// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009271RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 ASSERT(args.length() == 1);
9273 CONVERT_CHECKED(Smi, details, args[0]);
9274 int index = PropertyDetails(details).index();
9275 return Smi::FromInt(index);
9276}
9277
9278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279// Return property value from named interceptor.
9280// args[0]: object
9281// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284 ASSERT(args.length() == 2);
9285 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9286 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9287 CONVERT_ARG_CHECKED(String, name, 1);
9288
9289 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009290 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291}
9292
9293
9294// Return element value from indexed interceptor.
9295// args[0]: object
9296// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009297RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009298 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299 ASSERT(args.length() == 2);
9300 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9301 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9302 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9303
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009304 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305}
9306
9307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009308RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 ASSERT(args.length() >= 1);
9310 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009311 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009312 if (isolate->debug()->break_id() == 0 ||
9313 break_id != isolate->debug()->break_id()) {
9314 return isolate->Throw(
9315 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 }
9317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319}
9320
9321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009322RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324 ASSERT(args.length() == 1);
9325
9326 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009327 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9329 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009330 if (!maybe_result->ToObject(&result)) return maybe_result;
9331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332
9333 // Count all frames which are relevant to debugging stack trace.
9334 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009336 if (id == StackFrame::NO_ID) {
9337 // If there is no JavaScript stack frame count is 0.
9338 return Smi::FromInt(0);
9339 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009340 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 return Smi::FromInt(n);
9342}
9343
9344
9345static const int kFrameDetailsFrameIdIndex = 0;
9346static const int kFrameDetailsReceiverIndex = 1;
9347static const int kFrameDetailsFunctionIndex = 2;
9348static const int kFrameDetailsArgumentCountIndex = 3;
9349static const int kFrameDetailsLocalCountIndex = 4;
9350static const int kFrameDetailsSourcePositionIndex = 5;
9351static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009352static const int kFrameDetailsAtReturnIndex = 7;
9353static const int kFrameDetailsDebuggerFrameIndex = 8;
9354static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355
9356// Return an array with frame details
9357// args[0]: number: break id
9358// args[1]: number: frame index
9359//
9360// The array returned contains the following information:
9361// 0: Frame id
9362// 1: Receiver
9363// 2: Function
9364// 3: Argument count
9365// 4: Local count
9366// 5: Source position
9367// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009368// 7: Is at return
9369// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370// Arguments name, value
9371// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009372// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009373RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009374 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 ASSERT(args.length() == 2);
9376
9377 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009378 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009379 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9380 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009381 if (!maybe_check->ToObject(&check)) return maybe_check;
9382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009383 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009384 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385
9386 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009387 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009388 if (id == StackFrame::NO_ID) {
9389 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009392 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009393 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009394 for (; !it.done(); it.Advance()) {
9395 if (count == index) break;
9396 count++;
9397 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009400 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009401 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009402
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009403 // Traverse the saved contexts chain to find the active context for the
9404 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009405 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009406 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407 save = save->prev();
9408 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009409 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410
9411 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009412 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009413
9414 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009416 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009417
9418 // Check for constructor frame.
9419 bool constructor = it.frame()->IsConstructor();
9420
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009421 // Get scope info and read from it for local variable information.
9422 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009423 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009424 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425
9426 // Get the context.
9427 Handle<Context> context(Context::cast(it.frame()->context()));
9428
9429 // Get the locals names and values into a temporary array.
9430 //
9431 // TODO(1240907): Hide compiler-introduced stack variables
9432 // (e.g. .result)? For users of the debugger, they will probably be
9433 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434 Handle<FixedArray> locals =
9435 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009436
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009437 // Fill in the names of the locals.
9438 for (int i = 0; i < info.NumberOfLocals(); i++) {
9439 locals->set(i * 2, *info.LocalName(i));
9440 }
9441
9442 // Fill in the values of the locals.
9443 for (int i = 0; i < info.NumberOfLocals(); i++) {
9444 if (is_optimized_frame) {
9445 // If we are inspecting an optimized frame use undefined as the
9446 // value for all locals.
9447 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009448 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009449 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009451 } else if (i < info.number_of_stack_slots()) {
9452 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9454 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009455 // Traverse the context chain to the function context as all local
9456 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009457 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009458 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459 context = Handle<Context>(context->previous());
9460 }
9461 ASSERT(context->is_function_context());
9462 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009463 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 }
9465 }
9466
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009467 // Check whether this frame is positioned at return. If not top
9468 // frame or if the frame is optimized it cannot be at a return.
9469 bool at_return = false;
9470 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009472 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009473
9474 // If positioned just before return find the value to be returned and add it
9475 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009476 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009477 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009478 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009479 Address internal_frame_sp = NULL;
9480 while (!it2.done()) {
9481 if (it2.frame()->is_internal()) {
9482 internal_frame_sp = it2.frame()->sp();
9483 } else {
9484 if (it2.frame()->is_java_script()) {
9485 if (it2.frame()->id() == it.frame()->id()) {
9486 // The internal frame just before the JavaScript frame contains the
9487 // value to return on top. A debug break at return will create an
9488 // internal frame to store the return value (eax/rax/r0) before
9489 // entering the debug break exit frame.
9490 if (internal_frame_sp != NULL) {
9491 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 Handle<Object>(Memory::Object_at(internal_frame_sp),
9493 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009494 break;
9495 }
9496 }
9497 }
9498
9499 // Indicate that the previous frame was not an internal frame.
9500 internal_frame_sp = NULL;
9501 }
9502 it2.Advance();
9503 }
9504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505
9506 // Now advance to the arguments adapter frame (if any). It contains all
9507 // the provided parameters whereas the function frame always have the number
9508 // of arguments matching the functions parameters. The rest of the
9509 // information (except for what is collected above) is the same.
9510 it.AdvanceToArgumentsFrame();
9511
9512 // Find the number of arguments to fill. At least fill the number of
9513 // parameters for the function and fill more if more parameters are provided.
9514 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009515 if (argument_count < it.frame()->ComputeParametersCount()) {
9516 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009517 }
9518
9519 // Calculate the size of the result.
9520 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009521 2 * (argument_count + info.NumberOfLocals()) +
9522 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009524
9525 // Add the frame id.
9526 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9527
9528 // Add the function (same as in function frame).
9529 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9530
9531 // Add the arguments count.
9532 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9533
9534 // Add the locals count
9535 details->set(kFrameDetailsLocalCountIndex,
9536 Smi::FromInt(info.NumberOfLocals()));
9537
9538 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009539 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009540 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9541 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 }
9544
9545 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009547
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009548 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009551 // Add information on whether this frame is invoked in the debugger context.
9552 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 heap->ToBoolean(*save->context() ==
9554 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555
9556 // Fill the dynamic part.
9557 int details_index = kFrameDetailsFirstDynamicIndex;
9558
9559 // Add arguments name and value.
9560 for (int i = 0; i < argument_count; i++) {
9561 // Name of the argument.
9562 if (i < info.number_of_parameters()) {
9563 details->set(details_index++, *info.parameter_name(i));
9564 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566 }
9567
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009568 // Parameter value. If we are inspecting an optimized frame, use
9569 // undefined as the value.
9570 //
9571 // TODO(3141533): We should be able to get the actual parameter
9572 // value for optimized frames.
9573 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009574 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009575 details->set(details_index++, it.frame()->GetParameter(i));
9576 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578 }
9579 }
9580
9581 // Add locals name and value from the temporary copy from the function frame.
9582 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9583 details->set(details_index++, locals->get(i));
9584 }
9585
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009586 // Add the value being returned.
9587 if (at_return) {
9588 details->set(details_index++, *return_value);
9589 }
9590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009591 // Add the receiver (same as in function frame).
9592 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9593 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009595 if (!receiver->IsJSObject()) {
9596 // If the receiver is NOT a JSObject we have hit an optimization
9597 // where a value object is not converted into a wrapped JS objects.
9598 // To hide this optimization from the debugger, we wrap the receiver
9599 // by creating correct wrapper object based on the calling frame's
9600 // global context.
9601 it.Advance();
9602 Handle<Context> calling_frames_global_context(
9603 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 receiver =
9605 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606 }
9607 details->set(kFrameDetailsReceiverIndex, *receiver);
9608
9609 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009611}
9612
9613
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009614// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009615static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009616 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009617 Handle<SerializedScopeInfo> serialized_scope_info,
9618 ScopeInfo<>& scope_info,
9619 Handle<Context> context,
9620 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009621 // Fill all context locals to the context extension.
9622 for (int i = Context::MIN_CONTEXT_SLOTS;
9623 i < scope_info.number_of_context_slots();
9624 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009625 int context_index = serialized_scope_info->ContextSlotIndex(
9626 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009627
9628 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 if (*scope_info.context_slot_name(i) !=
9630 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009631 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009632 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009633 SetProperty(scope_object,
9634 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009636 NONE,
9637 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009638 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009639 }
9640 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009641
9642 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009643}
9644
9645
9646// Create a plain JSObject which materializes the local scope for the specified
9647// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009648static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9649 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009650 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009651 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009652 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9653 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009654
9655 // Allocate and initialize a JSObject with all the arguments, stack locals
9656 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009657 Handle<JSObject> local_scope =
9658 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009659
9660 // First fill all parameters.
9661 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009662 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009664 SetProperty(local_scope,
9665 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009667 NONE,
9668 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009669 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009670 }
9671
9672 // Second fill all stack locals.
9673 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009674 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009676 SetProperty(local_scope,
9677 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009679 NONE,
9680 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009681 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009682 }
9683
9684 // Third fill all context locals.
9685 Handle<Context> frame_context(Context::cast(frame->context()));
9686 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009687 if (!CopyContextLocalsToScopeObject(isolate,
9688 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009689 function_context, local_scope)) {
9690 return Handle<JSObject>();
9691 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009692
9693 // Finally copy any properties from the function context extension. This will
9694 // be variables introduced by eval.
9695 if (function_context->closure() == *function) {
9696 if (function_context->has_extension() &&
9697 !function_context->IsGlobalContext()) {
9698 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009699 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009700 for (int i = 0; i < keys->length(); i++) {
9701 // Names of variables introduced by eval are strings.
9702 ASSERT(keys->get(i)->IsString());
9703 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009704 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009706 SetProperty(local_scope,
9707 key,
9708 GetProperty(ext, key),
9709 NONE,
9710 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009711 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009712 }
9713 }
9714 }
9715 return local_scope;
9716}
9717
9718
9719// Create a plain JSObject which materializes the closure content for the
9720// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009721static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9722 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009723 ASSERT(context->is_function_context());
9724
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009725 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009726 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9727 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009728
9729 // Allocate and initialize a JSObject with all the content of theis function
9730 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731 Handle<JSObject> closure_scope =
9732 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009733
9734 // Check whether the arguments shadow object exists.
9735 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009736 shared->scope_info()->ContextSlotIndex(
9737 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009738 if (arguments_shadow_index >= 0) {
9739 // In this case all the arguments are available in the arguments shadow
9740 // object.
9741 Handle<JSObject> arguments_shadow(
9742 JSObject::cast(context->get(arguments_shadow_index)));
9743 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009744 // We don't expect exception-throwing getters on the arguments shadow.
9745 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009746 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009747 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009748 SetProperty(closure_scope,
9749 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009750 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009751 NONE,
9752 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009753 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009754 }
9755 }
9756
9757 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 if (!CopyContextLocalsToScopeObject(isolate,
9759 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009760 context, closure_scope)) {
9761 return Handle<JSObject>();
9762 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009763
9764 // Finally copy any properties from the function context extension. This will
9765 // be variables introduced by eval.
9766 if (context->has_extension()) {
9767 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009768 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009769 for (int i = 0; i < keys->length(); i++) {
9770 // Names of variables introduced by eval are strings.
9771 ASSERT(keys->get(i)->IsString());
9772 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 RETURN_IF_EMPTY_HANDLE_VALUE(
9774 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009775 SetProperty(closure_scope,
9776 key,
9777 GetProperty(ext, key),
9778 NONE,
9779 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009780 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009781 }
9782 }
9783
9784 return closure_scope;
9785}
9786
9787
9788// Iterate over the actual scopes visible from a stack frame. All scopes are
9789// backed by an actual context except the local scope, which is inserted
9790// "artifically" in the context chain.
9791class ScopeIterator {
9792 public:
9793 enum ScopeType {
9794 ScopeTypeGlobal = 0,
9795 ScopeTypeLocal,
9796 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009797 ScopeTypeClosure,
9798 // Every catch block contains an implicit with block (its parameter is
9799 // a JSContextExtensionObject) that extends current scope with a variable
9800 // holding exception object. Such with blocks are treated as scopes of their
9801 // own type.
9802 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009803 };
9804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009805 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9806 : isolate_(isolate),
9807 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009808 function_(JSFunction::cast(frame->function())),
9809 context_(Context::cast(frame->context())),
9810 local_done_(false),
9811 at_local_(false) {
9812
9813 // Check whether the first scope is actually a local scope.
9814 if (context_->IsGlobalContext()) {
9815 // If there is a stack slot for .result then this local scope has been
9816 // created for evaluating top level code and it is not a real local scope.
9817 // Checking for the existence of .result seems fragile, but the scope info
9818 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009819 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009821 at_local_ = index < 0;
9822 } else if (context_->is_function_context()) {
9823 at_local_ = true;
9824 }
9825 }
9826
9827 // More scopes?
9828 bool Done() { return context_.is_null(); }
9829
9830 // Move to the next scope.
9831 void Next() {
9832 // If at a local scope mark the local scope as passed.
9833 if (at_local_) {
9834 at_local_ = false;
9835 local_done_ = true;
9836
9837 // If the current context is not associated with the local scope the
9838 // current context is the next real scope, so don't move to the next
9839 // context in this case.
9840 if (context_->closure() != *function_) {
9841 return;
9842 }
9843 }
9844
9845 // The global scope is always the last in the chain.
9846 if (context_->IsGlobalContext()) {
9847 context_ = Handle<Context>();
9848 return;
9849 }
9850
9851 // Move to the next context.
9852 if (context_->is_function_context()) {
9853 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9854 } else {
9855 context_ = Handle<Context>(context_->previous());
9856 }
9857
9858 // If passing the local scope indicate that the current scope is now the
9859 // local scope.
9860 if (!local_done_ &&
9861 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9862 at_local_ = true;
9863 }
9864 }
9865
9866 // Return the type of the current scope.
9867 int Type() {
9868 if (at_local_) {
9869 return ScopeTypeLocal;
9870 }
9871 if (context_->IsGlobalContext()) {
9872 ASSERT(context_->global()->IsGlobalObject());
9873 return ScopeTypeGlobal;
9874 }
9875 if (context_->is_function_context()) {
9876 return ScopeTypeClosure;
9877 }
9878 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009879 // Current scope is either an explicit with statement or a with statement
9880 // implicitely generated for a catch block.
9881 // If the extension object here is a JSContextExtensionObject then
9882 // current with statement is one frome a catch block otherwise it's a
9883 // regular with statement.
9884 if (context_->extension()->IsJSContextExtensionObject()) {
9885 return ScopeTypeCatch;
9886 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009887 return ScopeTypeWith;
9888 }
9889
9890 // Return the JavaScript object with the content of the current scope.
9891 Handle<JSObject> ScopeObject() {
9892 switch (Type()) {
9893 case ScopeIterator::ScopeTypeGlobal:
9894 return Handle<JSObject>(CurrentContext()->global());
9895 break;
9896 case ScopeIterator::ScopeTypeLocal:
9897 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009898 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009899 break;
9900 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009901 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009902 // Return the with object.
9903 return Handle<JSObject>(CurrentContext()->extension());
9904 break;
9905 case ScopeIterator::ScopeTypeClosure:
9906 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009907 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009908 break;
9909 }
9910 UNREACHABLE();
9911 return Handle<JSObject>();
9912 }
9913
9914 // Return the context for this scope. For the local context there might not
9915 // be an actual context.
9916 Handle<Context> CurrentContext() {
9917 if (at_local_ && context_->closure() != *function_) {
9918 return Handle<Context>();
9919 }
9920 return context_;
9921 }
9922
9923#ifdef DEBUG
9924 // Debug print of the content of the current scope.
9925 void DebugPrint() {
9926 switch (Type()) {
9927 case ScopeIterator::ScopeTypeGlobal:
9928 PrintF("Global:\n");
9929 CurrentContext()->Print();
9930 break;
9931
9932 case ScopeIterator::ScopeTypeLocal: {
9933 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009934 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009935 scope_info.Print();
9936 if (!CurrentContext().is_null()) {
9937 CurrentContext()->Print();
9938 if (CurrentContext()->has_extension()) {
9939 Handle<JSObject> extension =
9940 Handle<JSObject>(CurrentContext()->extension());
9941 if (extension->IsJSContextExtensionObject()) {
9942 extension->Print();
9943 }
9944 }
9945 }
9946 break;
9947 }
9948
9949 case ScopeIterator::ScopeTypeWith: {
9950 PrintF("With:\n");
9951 Handle<JSObject> extension =
9952 Handle<JSObject>(CurrentContext()->extension());
9953 extension->Print();
9954 break;
9955 }
9956
ager@chromium.orga1645e22009-09-09 19:27:10 +00009957 case ScopeIterator::ScopeTypeCatch: {
9958 PrintF("Catch:\n");
9959 Handle<JSObject> extension =
9960 Handle<JSObject>(CurrentContext()->extension());
9961 extension->Print();
9962 break;
9963 }
9964
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009965 case ScopeIterator::ScopeTypeClosure: {
9966 PrintF("Closure:\n");
9967 CurrentContext()->Print();
9968 if (CurrentContext()->has_extension()) {
9969 Handle<JSObject> extension =
9970 Handle<JSObject>(CurrentContext()->extension());
9971 if (extension->IsJSContextExtensionObject()) {
9972 extension->Print();
9973 }
9974 }
9975 break;
9976 }
9977
9978 default:
9979 UNREACHABLE();
9980 }
9981 PrintF("\n");
9982 }
9983#endif
9984
9985 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009986 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009987 JavaScriptFrame* frame_;
9988 Handle<JSFunction> function_;
9989 Handle<Context> context_;
9990 bool local_done_;
9991 bool at_local_;
9992
9993 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9994};
9995
9996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009997RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009999 ASSERT(args.length() == 2);
10000
10001 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010002 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010003 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10004 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010005 if (!maybe_check->ToObject(&check)) return maybe_check;
10006 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010007 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10008
10009 // Get the frame where the debugging is performed.
10010 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010011 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010012 JavaScriptFrame* frame = it.frame();
10013
10014 // Count the visible scopes.
10015 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010017 n++;
10018 }
10019
10020 return Smi::FromInt(n);
10021}
10022
10023
10024static const int kScopeDetailsTypeIndex = 0;
10025static const int kScopeDetailsObjectIndex = 1;
10026static const int kScopeDetailsSize = 2;
10027
10028// Return an array with scope details
10029// args[0]: number: break id
10030// args[1]: number: frame index
10031// args[2]: number: scope index
10032//
10033// The array returned contains the following information:
10034// 0: Scope type
10035// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010038 ASSERT(args.length() == 3);
10039
10040 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010041 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010042 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10043 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010044 if (!maybe_check->ToObject(&check)) return maybe_check;
10045 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010046 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10047 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10048
10049 // Get the frame where the debugging is performed.
10050 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010051 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010052 JavaScriptFrame* frame = frame_it.frame();
10053
10054 // Find the requested scope.
10055 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010057 for (; !it.Done() && n < index; it.Next()) {
10058 n++;
10059 }
10060 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010062 }
10063
10064 // Calculate the size of the result.
10065 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010067
10068 // Fill in scope details.
10069 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010070 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010071 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010072 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010074 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010075}
10076
10077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010078RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010079 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010080 ASSERT(args.length() == 0);
10081
10082#ifdef DEBUG
10083 // Print the scopes for the top frame.
10084 StackFrameLocator locator;
10085 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010087 it.DebugPrint();
10088 }
10089#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010091}
10092
10093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010094RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010096 ASSERT(args.length() == 1);
10097
10098 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010099 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010100 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10101 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010102 if (!maybe_result->ToObject(&result)) return maybe_result;
10103 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010104
10105 // Count all archived V8 threads.
10106 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 for (ThreadState* thread =
10108 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010109 thread != NULL;
10110 thread = thread->Next()) {
10111 n++;
10112 }
10113
10114 // Total number of threads is current thread and archived threads.
10115 return Smi::FromInt(n + 1);
10116}
10117
10118
10119static const int kThreadDetailsCurrentThreadIndex = 0;
10120static const int kThreadDetailsThreadIdIndex = 1;
10121static const int kThreadDetailsSize = 2;
10122
10123// Return an array with thread details
10124// args[0]: number: break id
10125// args[1]: number: thread index
10126//
10127// The array returned contains the following information:
10128// 0: Is current thread?
10129// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010130RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010131 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010132 ASSERT(args.length() == 2);
10133
10134 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010135 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10137 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010138 if (!maybe_check->ToObject(&check)) return maybe_check;
10139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010140 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10141
10142 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 Handle<FixedArray> details =
10144 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010145
10146 // Thread index 0 is current thread.
10147 if (index == 0) {
10148 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010149 details->set(kThreadDetailsCurrentThreadIndex,
10150 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010151 details->set(kThreadDetailsThreadIdIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 Smi::FromInt(
10153 isolate->thread_manager()->CurrentId()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010154 } else {
10155 // Find the thread with the requested index.
10156 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010157 ThreadState* thread =
10158 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010159 while (index != n && thread != NULL) {
10160 thread = thread->Next();
10161 n++;
10162 }
10163 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010165 }
10166
10167 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010168 details->set(kThreadDetailsCurrentThreadIndex,
10169 isolate->heap()->false_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010170 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
10171 }
10172
10173 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010175}
10176
10177
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010178// Sets the disable break state
10179// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010180RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010182 ASSERT(args.length() == 1);
10183 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010184 isolate->debug()->set_disable_break(disable_break);
10185 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010186}
10187
10188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010189RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010191 ASSERT(args.length() == 1);
10192
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010193 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10194 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195 // Find the number of break points
10196 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010197 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010198 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 Handle<FixedArray>::cast(break_locations));
10201}
10202
10203
10204// Set a break point in a function
10205// args[0]: function
10206// args[1]: number: break source position (within the function source)
10207// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010208RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010211 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10212 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010213 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10214 RUNTIME_ASSERT(source_position >= 0);
10215 Handle<Object> break_point_object_arg = args.at<Object>(2);
10216
10217 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10219 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010220
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010221 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222}
10223
10224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10226 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010227 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 // Iterate the heap looking for SharedFunctionInfo generated from the
10229 // script. The inner most SharedFunctionInfo containing the source position
10230 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010231 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 // which is found is not compiled it is compiled and the heap is iterated
10233 // again as the compilation might create inner functions from the newly
10234 // compiled function and the actual requested break point might be in one of
10235 // these functions.
10236 bool done = false;
10237 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010238 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 while (!done) {
10241 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010242 for (HeapObject* obj = iterator.next();
10243 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 if (obj->IsSharedFunctionInfo()) {
10245 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10246 if (shared->script() == *script) {
10247 // If the SharedFunctionInfo found has the requested script data and
10248 // contains the source position it is a candidate.
10249 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010250 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 start_position = shared->start_position();
10252 }
10253 if (start_position <= position &&
10254 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010255 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 // candidate this is the new candidate.
10257 if (target.is_null()) {
10258 target_start_position = start_position;
10259 target = shared;
10260 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010261 if (target_start_position == start_position &&
10262 shared->end_position() == target->end_position()) {
10263 // If a top-level function contain only one function
10264 // declartion the source for the top-level and the function is
10265 // the same. In that case prefer the non top-level function.
10266 if (!shared->is_toplevel()) {
10267 target_start_position = start_position;
10268 target = shared;
10269 }
10270 } else if (target_start_position <= start_position &&
10271 shared->end_position() <= target->end_position()) {
10272 // This containment check includes equality as a function inside
10273 // a top-level function can share either start or end position
10274 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 target_start_position = start_position;
10276 target = shared;
10277 }
10278 }
10279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 }
10281 }
10282 }
10283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 }
10287
10288 // If the candidate found is compiled we are done. NOTE: when lazy
10289 // compilation of inner functions is introduced some additional checking
10290 // needs to be done here to compile inner functions.
10291 done = target->is_compiled();
10292 if (!done) {
10293 // If the candidate is not compiled compile it to reveal any inner
10294 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010295 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 }
10297 }
10298
10299 return *target;
10300}
10301
10302
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010303// Changes the state of a break point in a script and returns source position
10304// where break point was set. NOTE: Regarding performance see the NOTE for
10305// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306// args[0]: script to set break point in
10307// args[1]: number: break source position (within the script source)
10308// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010309RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010310 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 ASSERT(args.length() == 3);
10312 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10313 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10314 RUNTIME_ASSERT(source_position >= 0);
10315 Handle<Object> break_point_object_arg = args.at<Object>(2);
10316
10317 // Get the script from the script wrapper.
10318 RUNTIME_ASSERT(wrapper->value()->IsScript());
10319 Handle<Script> script(Script::cast(wrapper->value()));
10320
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010321 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 if (!result->IsUndefined()) {
10324 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10325 // Find position within function. The script position might be before the
10326 // source position of the first function.
10327 int position;
10328 if (shared->start_position() > source_position) {
10329 position = 0;
10330 } else {
10331 position = source_position - shared->start_position();
10332 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010334 position += shared->start_position();
10335 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338}
10339
10340
10341// Clear a break point
10342// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010343RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010344 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345 ASSERT(args.length() == 1);
10346 Handle<Object> break_point_object_arg = args.at<Object>(0);
10347
10348 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352}
10353
10354
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010355// Change the state of break on exceptions.
10356// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10357// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010358RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010359 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010361 RUNTIME_ASSERT(args[0]->IsNumber());
10362 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010364 // If the number doesn't match an enum value, the ChangeBreakOnException
10365 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 ExceptionBreakType type =
10367 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010368 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010369 isolate->debug()->ChangeBreakOnException(type, enable);
10370 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371}
10372
10373
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010374// Returns the state of break on exceptions
10375// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010376RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010377 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010378 ASSERT(args.length() == 1);
10379 RUNTIME_ASSERT(args[0]->IsNumber());
10380
10381 ExceptionBreakType type =
10382 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010384 return Smi::FromInt(result);
10385}
10386
10387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388// Prepare for stepping
10389// args[0]: break id for checking execution state
10390// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010391// args[2]: number of times to perform the step, for step out it is the number
10392// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010393RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 ASSERT(args.length() == 3);
10396 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010397 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010398 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10399 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010400 if (!maybe_check->ToObject(&check)) return maybe_check;
10401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010404 }
10405
10406 // Get the step action and check validity.
10407 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10408 if (step_action != StepIn &&
10409 step_action != StepNext &&
10410 step_action != StepOut &&
10411 step_action != StepInMin &&
10412 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 }
10415
10416 // Get the number of steps.
10417 int step_count = NumberToInt32(args[2]);
10418 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 }
10421
ager@chromium.orga1645e22009-09-09 19:27:10 +000010422 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010423 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10427 step_count);
10428 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010429}
10430
10431
10432// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010433RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010435 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010436 isolate->debug()->ClearStepping();
10437 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438}
10439
10440
10441// Creates a copy of the with context chain. The copy of the context chain is
10442// is linked to the function context supplied.
10443static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10444 Handle<Context> function_context) {
10445 // At the bottom of the chain. Return the function context to link to.
10446 if (context_chain->is_function_context()) {
10447 return function_context;
10448 }
10449
10450 // Recursively copy the with contexts.
10451 Handle<Context> previous(context_chain->previous());
10452 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010453 Handle<Context> context = CopyWithContextChain(function_context, previous);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 return context->GetIsolate()->factory()->NewWithContext(
10455 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010456}
10457
10458
10459// Helper function to find or create the arguments object for
10460// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461static Handle<Object> GetArgumentsObject(Isolate* isolate,
10462 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010463 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010464 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 const ScopeInfo<>* sinfo,
10466 Handle<Context> function_context) {
10467 // Try to find the value of 'arguments' to pass as parameter. If it is not
10468 // found (that is the debugged function does not reference 'arguments' and
10469 // does not support eval) then create an 'arguments' object.
10470 int index;
10471 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 }
10476 }
10477
10478 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10480 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 }
10484 }
10485
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010486 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 Handle<JSObject> arguments =
10488 isolate->factory()->NewArgumentsObject(function, length);
10489 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010490
10491 AssertNoAllocation no_gc;
10492 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010494 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010496 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497 return arguments;
10498}
10499
10500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501static const char kSourceStr[] =
10502 "(function(arguments,__source__){return eval(__source__);})";
10503
10504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010506// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507// extension part has all the parameters and locals of the function on the
10508// stack frame. A function which calls eval with the code to evaluate is then
10509// compiled in this context and called in this context. As this context
10510// replaces the context of the function on the stack frame a new (empty)
10511// function is created as well to be used as the closure for the context.
10512// This function and the context acts as replacements for the function on the
10513// stack frame presenting the same view of the values of parameters and
10514// local variables as if the piece of JavaScript was evaluated at the point
10515// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010516RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518
10519 // Check the execution state and decode arguments frame and source to be
10520 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010521 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010522 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010523 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10524 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010525 if (!maybe_check_result->ToObject(&check_result)) {
10526 return maybe_check_result;
10527 }
10528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10530 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010531 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010532 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010533
10534 // Handle the processing of break.
10535 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536
10537 // Get the frame where the debugging is performed.
10538 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010539 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 JavaScriptFrame* frame = it.frame();
10541 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010542 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010543 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544
10545 // Traverse the saved contexts chain to find the active context for the
10546 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010547 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010548 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 save = save->prev();
10550 }
10551 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 SaveContext savex(isolate);
10553 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554
10555 // Create the (empty) function replacing the function on the stack frame for
10556 // the purpose of evaluating in the context created below. It is important
10557 // that this function does not describe any parameters and local variables
10558 // in the context. If it does then this will cause problems with the lookup
10559 // in Context::Lookup, where context slots for parameters and local variables
10560 // are looked at before the extension object.
10561 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010562 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10563 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 go_between->set_context(function->context());
10565#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010566 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10568 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10569#endif
10570
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010571 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10573 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574
10575 // Allocate a new context for the debug evaluation and set the extension
10576 // object build.
10577 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10579 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010580 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010582 Handle<Context> frame_context(Context::cast(frame->context()));
10583 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 context = CopyWithContextChain(frame_context, context);
10585
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010586 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010588 Handle<JSObject>::cast(additional_context), false);
10589 }
10590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 // Wrap the evaluation statement in a new function compiled in the newly
10592 // created context. The function has one parameter which has to be called
10593 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010594 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 isolate->factory()->NewStringFromAscii(
10599 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010600
10601 // Currently, the eval code will be executed in non-strict mode,
10602 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010603 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010604 Compiler::CompileEval(function_source,
10605 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010606 context->IsGlobalContext(),
10607 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010608 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611
10612 // Invoke the result of the compilation to get the evaluation function.
10613 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 Handle<Object> evaluation_function =
10616 Execution::Call(compiled_function, receiver, 0, NULL,
10617 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010618 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10621 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010622 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623
10624 // Invoke the evaluation function and return the result.
10625 const int argc = 2;
10626 Object** argv[argc] = { arguments.location(),
10627 Handle<Object>::cast(source).location() };
10628 Handle<Object> result =
10629 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10630 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010631 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010632
10633 // Skip the global proxy as it has no properties and always delegates to the
10634 // real global object.
10635 if (result->IsJSGlobalProxy()) {
10636 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10637 }
10638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 return *result;
10640}
10641
10642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010643RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010645
10646 // Check the execution state and decode arguments frame and source to be
10647 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010648 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010649 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010650 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10651 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010652 if (!maybe_check_result->ToObject(&check_result)) {
10653 return maybe_check_result;
10654 }
10655 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010657 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010658 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010659
10660 // Handle the processing of break.
10661 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010662
10663 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010664 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010666 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 top = top->prev();
10668 }
10669 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 }
10672
10673 // Get the global context now set to the top context from before the
10674 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010675 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010677 bool is_global = true;
10678
10679 if (additional_context->IsJSObject()) {
10680 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10682 isolate->factory()->empty_string(),
10683 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010684 go_between->set_context(*context);
10685 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 isolate->factory()->NewFunctionContext(
10687 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010688 context->set_extension(JSObject::cast(*additional_context));
10689 is_global = false;
10690 }
10691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010693 // Currently, the eval code will be executed in non-strict mode,
10694 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010695 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010696 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010697 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010699 Handle<JSFunction>(
10700 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10701 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702
10703 // Invoke the result of the compilation to get the evaluation function.
10704 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 Handle<Object> result =
10707 Execution::Call(compiled_function, receiver, 0, NULL,
10708 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010709 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 return *result;
10711}
10712
10713
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010714RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010715 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010716 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010719 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720
10721 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010722 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010723 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10724 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10725 // because using
10726 // instances->set(i, *GetScriptWrapper(script))
10727 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10728 // already have deferenced the instances handle.
10729 Handle<JSValue> wrapper = GetScriptWrapper(script);
10730 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731 }
10732
10733 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 Handle<JSObject> result =
10735 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736 Handle<JSArray>::cast(result)->SetContent(*instances);
10737 return *result;
10738}
10739
10740
10741// Helper function used by Runtime_DebugReferencedBy below.
10742static int DebugReferencedBy(JSObject* target,
10743 Object* instance_filter, int max_references,
10744 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745 JSFunction* arguments_function) {
10746 NoHandleAllocation ha;
10747 AssertNoAllocation no_alloc;
10748
10749 // Iterate the heap.
10750 int count = 0;
10751 JSObject* last = NULL;
10752 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010753 HeapObject* heap_obj = NULL;
10754 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755 (max_references == 0 || count < max_references)) {
10756 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757 if (heap_obj->IsJSObject()) {
10758 // Skip context extension objects and argument arrays as these are
10759 // checked in the context of functions using them.
10760 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010761 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 obj->map()->constructor() == arguments_function) {
10763 continue;
10764 }
10765
10766 // Check if the JS object has a reference to the object looked for.
10767 if (obj->ReferencesObject(target)) {
10768 // Check instance filter if supplied. This is normally used to avoid
10769 // references from mirror objects (see Runtime_IsInPrototypeChain).
10770 if (!instance_filter->IsUndefined()) {
10771 Object* V = obj;
10772 while (true) {
10773 Object* prototype = V->GetPrototype();
10774 if (prototype->IsNull()) {
10775 break;
10776 }
10777 if (instance_filter == prototype) {
10778 obj = NULL; // Don't add this object.
10779 break;
10780 }
10781 V = prototype;
10782 }
10783 }
10784
10785 if (obj != NULL) {
10786 // Valid reference found add to instance array if supplied an update
10787 // count.
10788 if (instances != NULL && count < instances_size) {
10789 instances->set(count, obj);
10790 }
10791 last = obj;
10792 count++;
10793 }
10794 }
10795 }
10796 }
10797
10798 // Check for circular reference only. This can happen when the object is only
10799 // referenced from mirrors and has a circular reference in which case the
10800 // object is not really alive and would have been garbage collected if not
10801 // referenced from the mirror.
10802 if (count == 1 && last == target) {
10803 count = 0;
10804 }
10805
10806 // Return the number of referencing objects found.
10807 return count;
10808}
10809
10810
10811// Scan the heap for objects with direct references to an object
10812// args[0]: the object to find references to
10813// args[1]: constructor function for instances to exclude (Mirror)
10814// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010815RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 ASSERT(args.length() == 3);
10817
10818 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820
10821 // Check parameters.
10822 CONVERT_CHECKED(JSObject, target, args[0]);
10823 Object* instance_filter = args[1];
10824 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10825 instance_filter->IsJSObject());
10826 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10827 RUNTIME_ASSERT(max_references >= 0);
10828
10829 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 JSFunction* arguments_function =
10833 JSFunction::cast(arguments_boilerplate->map()->constructor());
10834
10835 // Get the number of referencing objects.
10836 int count;
10837 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010838 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839
10840 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010841 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010843 if (!maybe_object->ToObject(&object)) return maybe_object;
10844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845 FixedArray* instances = FixedArray::cast(object);
10846
10847 // Fill the referencing objects.
10848 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010849 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
10851 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010852 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10854 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010855 if (!maybe_result->ToObject(&result)) return maybe_result;
10856 }
10857 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010858 return result;
10859}
10860
10861
10862// Helper function used by Runtime_DebugConstructedBy below.
10863static int DebugConstructedBy(JSFunction* constructor, int max_references,
10864 FixedArray* instances, int instances_size) {
10865 AssertNoAllocation no_alloc;
10866
10867 // Iterate the heap.
10868 int count = 0;
10869 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010870 HeapObject* heap_obj = NULL;
10871 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872 (max_references == 0 || count < max_references)) {
10873 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874 if (heap_obj->IsJSObject()) {
10875 JSObject* obj = JSObject::cast(heap_obj);
10876 if (obj->map()->constructor() == constructor) {
10877 // Valid reference found add to instance array if supplied an update
10878 // count.
10879 if (instances != NULL && count < instances_size) {
10880 instances->set(count, obj);
10881 }
10882 count++;
10883 }
10884 }
10885 }
10886
10887 // Return the number of referencing objects found.
10888 return count;
10889}
10890
10891
10892// Scan the heap for objects constructed by a specific function.
10893// args[0]: the constructor to find instances of
10894// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010895RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896 ASSERT(args.length() == 2);
10897
10898 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900
10901 // Check parameters.
10902 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10903 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10904 RUNTIME_ASSERT(max_references >= 0);
10905
10906 // Get the number of referencing objects.
10907 int count;
10908 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10909
10910 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010911 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010913 if (!maybe_object->ToObject(&object)) return maybe_object;
10914 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010915 FixedArray* instances = FixedArray::cast(object);
10916
10917 // Fill the referencing objects.
10918 count = DebugConstructedBy(constructor, max_references, instances, count);
10919
10920 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010921 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10923 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010924 if (!maybe_result->ToObject(&result)) return maybe_result;
10925 }
10926 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 return result;
10928}
10929
10930
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010931// Find the effective prototype object as returned by __proto__.
10932// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010933RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 ASSERT(args.length() == 1);
10935
10936 CONVERT_CHECKED(JSObject, obj, args[0]);
10937
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010938 // Use the __proto__ accessor.
10939 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940}
10941
10942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010943RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000010944 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947}
10948
10949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010950RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010951#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010952 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010953 ASSERT(args.length() == 1);
10954 // Get the function and make sure it is compiled.
10955 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010956 Handle<SharedFunctionInfo> shared(func->shared());
10957 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010958 return Failure::Exception();
10959 }
10960 func->code()->PrintLn();
10961#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010963}
ager@chromium.org9085a012009-05-11 19:22:57 +000010964
10965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010966RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010967#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010968 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010969 ASSERT(args.length() == 1);
10970 // Get the function and make sure it is compiled.
10971 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010972 Handle<SharedFunctionInfo> shared(func->shared());
10973 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010974 return Failure::Exception();
10975 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010976 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010977#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010979}
10980
10981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010982RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010983 NoHandleAllocation ha;
10984 ASSERT(args.length() == 1);
10985
10986 CONVERT_CHECKED(JSFunction, f, args[0]);
10987 return f->shared()->inferred_name();
10988}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010989
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010990
10991static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010992 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010993 AssertNoAllocation no_allocations;
10994
10995 int counter = 0;
10996 int buffer_size = buffer->length();
10997 HeapIterator iterator;
10998 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10999 ASSERT(obj != NULL);
11000 if (!obj->IsSharedFunctionInfo()) {
11001 continue;
11002 }
11003 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11004 if (shared->script() != script) {
11005 continue;
11006 }
11007 if (counter < buffer_size) {
11008 buffer->set(counter, shared);
11009 }
11010 counter++;
11011 }
11012 return counter;
11013}
11014
11015// For a script finds all SharedFunctionInfo's in the heap that points
11016// to this script. Returns JSArray of SharedFunctionInfo wrapped
11017// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011018RUNTIME_FUNCTION(MaybeObject*,
11019 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011020 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011021 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011022 CONVERT_CHECKED(JSValue, script_value, args[0]);
11023
11024 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11025
11026 const int kBufferSize = 32;
11027
11028 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011029 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011030 int number = FindSharedFunctionInfosForScript(*script, *array);
11031 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011032 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011033 FindSharedFunctionInfosForScript(*script, *array);
11034 }
11035
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011036 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011037 result->set_length(Smi::FromInt(number));
11038
11039 LiveEdit::WrapSharedFunctionInfos(result);
11040
11041 return *result;
11042}
11043
11044// For a script calculates compilation information about all its functions.
11045// The script source is explicitly specified by the second argument.
11046// The source of the actual script is not used, however it is important that
11047// all generated code keeps references to this particular instance of script.
11048// Returns a JSArray of compilation infos. The array is ordered so that
11049// each function with all its descendant is always stored in a continues range
11050// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011051RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011052 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011054 CONVERT_CHECKED(JSValue, script, args[0]);
11055 CONVERT_ARG_CHECKED(String, source, 1);
11056 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11057
11058 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011061 return Failure::Exception();
11062 }
11063
11064 return result;
11065}
11066
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011067// Changes the source of the script to a new_source.
11068// If old_script_name is provided (i.e. is a String), also creates a copy of
11069// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011070RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011071 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011073 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11074 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011075 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011076
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011077 CONVERT_CHECKED(Script, original_script_pointer,
11078 original_script_value->value());
11079 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011080
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011081 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11082 new_source,
11083 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011084
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011085 if (old_script->IsScript()) {
11086 Handle<Script> script_handle(Script::cast(old_script));
11087 return *(GetScriptWrapper(script_handle));
11088 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011089 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011090 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011091}
11092
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011094RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011095 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011096 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011097 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11098 return LiveEdit::FunctionSourceUpdated(shared_info);
11099}
11100
11101
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011102// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011103RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011104 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011106 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11107 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11108
ager@chromium.orgac091b72010-05-05 07:34:42 +000011109 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011110}
11111
11112// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011113RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011114 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011115 HandleScope scope(isolate);
11116 Handle<Object> function_object(args[0], isolate);
11117 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011118
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011119 if (function_object->IsJSValue()) {
11120 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11121 if (script_object->IsJSValue()) {
11122 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011124 }
11125
11126 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11127 } else {
11128 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11129 // and we check it in this function.
11130 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011131
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011132 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011133}
11134
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011135
11136// In a code of a parent function replaces original function as embedded object
11137// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011138RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011139 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011141
11142 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11143 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11144 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11145
11146 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11147 subst_wrapper);
11148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011149 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011150}
11151
11152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011153// Updates positions of a shared function info (first parameter) according
11154// to script source change. Text change is described in second parameter as
11155// array of groups of 3 numbers:
11156// (change_begin, change_end, change_end_new_position).
11157// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011158RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011159 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011160 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011161 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11162 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11163
ager@chromium.orgac091b72010-05-05 07:34:42 +000011164 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011165}
11166
11167
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011168// For array of SharedFunctionInfo's (each wrapped in JSValue)
11169// checks that none of them have activations on stacks (of any thread).
11170// Returns array of the same length with corresponding results of
11171// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011172RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011173 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011174 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011175 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011176 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011177
ager@chromium.org357bf652010-04-12 11:30:10 +000011178 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011179}
11180
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011181// Compares 2 strings line-by-line, then token-wise and returns diff in form
11182// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11183// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011185 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011187 CONVERT_ARG_CHECKED(String, s1, 0);
11188 CONVERT_ARG_CHECKED(String, s2, 1);
11189
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011190 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011191}
11192
11193
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011194// A testing entry. Returns statement position which is the closest to
11195// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011196RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011197 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011198 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011199 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11200 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011203
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011204 if (code->kind() != Code::FUNCTION &&
11205 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011207 }
11208
11209 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011210 int closest_pc = 0;
11211 int distance = kMaxInt;
11212 while (!it.done()) {
11213 int statement_position = static_cast<int>(it.rinfo()->data());
11214 // Check if this break point is closer that what was previously found.
11215 if (source_position <= statement_position &&
11216 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011217 closest_pc =
11218 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011219 distance = statement_position - source_position;
11220 // Check whether we can't get any closer.
11221 if (distance == 0) break;
11222 }
11223 it.next();
11224 }
11225
11226 return Smi::FromInt(closest_pc);
11227}
11228
11229
ager@chromium.org357bf652010-04-12 11:30:10 +000011230// Calls specified function with or without entering the debugger.
11231// This is used in unit tests to run code as if debugger is entered or simply
11232// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011233RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011234 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011235 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011236 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11237 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11238
11239 Handle<Object> result;
11240 bool pending_exception;
11241 {
11242 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011244 &pending_exception);
11245 } else {
11246 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011248 &pending_exception);
11249 }
11250 }
11251 if (!pending_exception) {
11252 return *result;
11253 } else {
11254 return Failure::Exception();
11255 }
11256}
11257
11258
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011259// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011260RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011261 CONVERT_CHECKED(String, arg, args[0]);
11262 SmartPointer<char> flags =
11263 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11264 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011266}
11267
11268
11269// Performs a GC.
11270// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011271RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 isolate->heap()->CollectAllGarbage(true);
11273 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011274}
11275
11276
11277// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011278RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011279 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011280 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011281 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011282 }
11283 return Smi::FromInt(usage);
11284}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011285
11286
11287// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011288RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011289#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011290 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011291#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011292 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011293#endif
11294}
11295
11296
11297// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011298RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011299#ifdef LIVE_OBJECT_LIST
11300 return LiveObjectList::Capture();
11301#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011303#endif
11304}
11305
11306
11307// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011308RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011309#ifdef LIVE_OBJECT_LIST
11310 CONVERT_SMI_CHECKED(id, args[0]);
11311 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 return success ? isolate->heap()->true_value() :
11313 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011314#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011316#endif
11317}
11318
11319
11320// Generates the response to a debugger request for a dump of the objects
11321// contained in the difference between the captured live object lists
11322// specified by id1 and id2.
11323// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11324// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011325RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011326#ifdef LIVE_OBJECT_LIST
11327 HandleScope scope;
11328 CONVERT_SMI_CHECKED(id1, args[0]);
11329 CONVERT_SMI_CHECKED(id2, args[1]);
11330 CONVERT_SMI_CHECKED(start, args[2]);
11331 CONVERT_SMI_CHECKED(count, args[3]);
11332 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11333 EnterDebugger enter_debugger;
11334 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11335#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011337#endif
11338}
11339
11340
11341// Gets the specified object as requested by the debugger.
11342// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011343RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011344#ifdef LIVE_OBJECT_LIST
11345 CONVERT_SMI_CHECKED(obj_id, args[0]);
11346 Object* result = LiveObjectList::GetObj(obj_id);
11347 return result;
11348#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011350#endif
11351}
11352
11353
11354// Gets the obj id for the specified address if valid.
11355// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011356RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011357#ifdef LIVE_OBJECT_LIST
11358 HandleScope scope;
11359 CONVERT_ARG_CHECKED(String, address, 0);
11360 Object* result = LiveObjectList::GetObjId(address);
11361 return result;
11362#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011364#endif
11365}
11366
11367
11368// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011369RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011370#ifdef LIVE_OBJECT_LIST
11371 HandleScope scope;
11372 CONVERT_SMI_CHECKED(obj_id, args[0]);
11373 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11374 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11375 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11376 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11377 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11378
11379 Handle<JSObject> instance_filter;
11380 if (args[1]->IsJSObject()) {
11381 instance_filter = args.at<JSObject>(1);
11382 }
11383 bool verbose = false;
11384 if (args[2]->IsBoolean()) {
11385 verbose = args[2]->IsTrue();
11386 }
11387 int start = 0;
11388 if (args[3]->IsSmi()) {
11389 start = Smi::cast(args[3])->value();
11390 }
11391 int limit = Smi::kMaxValue;
11392 if (args[4]->IsSmi()) {
11393 limit = Smi::cast(args[4])->value();
11394 }
11395
11396 return LiveObjectList::GetObjRetainers(obj_id,
11397 instance_filter,
11398 verbose,
11399 start,
11400 limit,
11401 filter_obj);
11402#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011404#endif
11405}
11406
11407
11408// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011410#ifdef LIVE_OBJECT_LIST
11411 HandleScope scope;
11412 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11413 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11414 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11415
11416 Handle<JSObject> instance_filter;
11417 if (args[2]->IsJSObject()) {
11418 instance_filter = args.at<JSObject>(2);
11419 }
11420
11421 Object* result =
11422 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11423 return result;
11424#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011426#endif
11427}
11428
11429
11430// Generates the response to a debugger request for a list of all
11431// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011432RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011433#ifdef LIVE_OBJECT_LIST
11434 CONVERT_SMI_CHECKED(start, args[0]);
11435 CONVERT_SMI_CHECKED(count, args[1]);
11436 return LiveObjectList::Info(start, count);
11437#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011439#endif
11440}
11441
11442
11443// Gets a dump of the specified object as requested by the debugger.
11444// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011445RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011446#ifdef LIVE_OBJECT_LIST
11447 HandleScope scope;
11448 CONVERT_SMI_CHECKED(obj_id, args[0]);
11449 Object* result = LiveObjectList::PrintObj(obj_id);
11450 return result;
11451#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011453#endif
11454}
11455
11456
11457// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011458RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011459#ifdef LIVE_OBJECT_LIST
11460 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011462#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011464#endif
11465}
11466
11467
11468// Generates the response to a debugger request for a summary of the types
11469// of objects in the difference between the captured live object lists
11470// specified by id1 and id2.
11471// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11472// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011473RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011474#ifdef LIVE_OBJECT_LIST
11475 HandleScope scope;
11476 CONVERT_SMI_CHECKED(id1, args[0]);
11477 CONVERT_SMI_CHECKED(id2, args[1]);
11478 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11479
11480 EnterDebugger enter_debugger;
11481 return LiveObjectList::Summarize(id1, id2, filter_obj);
11482#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011484#endif
11485}
11486
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011487#endif // ENABLE_DEBUGGER_SUPPORT
11488
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011489
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011490#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011491RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011492 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011493 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011494
11495 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011496 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11497 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011499}
11500
11501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011502RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011503 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011504 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011505
11506 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011507 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11508 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011509 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011510}
11511
11512#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011514// Finds the script object from the script data. NOTE: This operation uses
11515// heap traversal to find the function generated for the source position
11516// for the requested break point. For lazily compiled functions several heap
11517// traversals might be required rendering this operation as a rather slow
11518// operation. However for setting break points which is normally done through
11519// some kind of user interaction the performance is not crucial.
11520static Handle<Object> Runtime_GetScriptFromScriptName(
11521 Handle<String> script_name) {
11522 // Scan the heap for Script objects to find the script with the requested
11523 // script data.
11524 Handle<Script> script;
11525 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011526 HeapObject* obj = NULL;
11527 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528 // If a script is found check if it has the script data requested.
11529 if (obj->IsScript()) {
11530 if (Script::cast(obj)->name()->IsString()) {
11531 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11532 script = Handle<Script>(Script::cast(obj));
11533 }
11534 }
11535 }
11536 }
11537
11538 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540
11541 // Return the script found.
11542 return GetScriptWrapper(script);
11543}
11544
11545
11546// Get the script object from script data. NOTE: Regarding performance
11547// see the NOTE for GetScriptFromScriptData.
11548// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011549RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011551
11552 ASSERT(args.length() == 1);
11553
11554 CONVERT_CHECKED(String, script_name, args[0]);
11555
11556 // Find the requested script.
11557 Handle<Object> result =
11558 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11559 return *result;
11560}
11561
11562
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011563// Determines whether the given stack frame should be displayed in
11564// a stack trace. The caller is the error constructor that asked
11565// for the stack trace to be collected. The first time a construct
11566// call to this function is encountered it is skipped. The seen_caller
11567// in/out parameter is used to remember if the caller has been seen
11568// yet.
11569static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11570 bool* seen_caller) {
11571 // Only display JS frames.
11572 if (!raw_frame->is_java_script())
11573 return false;
11574 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11575 Object* raw_fun = frame->function();
11576 // Not sure when this can happen but skip it just in case.
11577 if (!raw_fun->IsJSFunction())
11578 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011579 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011580 *seen_caller = true;
11581 return false;
11582 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011583 // Skip all frames until we've seen the caller. Also, skip the most
11584 // obvious builtin calls. Some builtin calls (such as Number.ADD
11585 // which is invoked using 'call') are very difficult to recognize
11586 // so we're leaving them in for now.
11587 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011588}
11589
11590
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011591// Collect the raw data for a stack trace. Returns an array of 4
11592// element segments each containing a receiver, function, code and
11593// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011595 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011596 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011597 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011599 HandleScope scope(isolate);
11600 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011601
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011602 limit = Max(limit, 0); // Ensure that limit is not negative.
11603 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011604 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011606
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011607 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011608 // If the caller parameter is a function we skip frames until we're
11609 // under it before starting to collect.
11610 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011611 int cursor = 0;
11612 int frames_seen = 0;
11613 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011614 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011615 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011616 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011617 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011618 // Set initial size to the maximum inlining level + 1 for the outermost
11619 // function.
11620 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011621 frame->Summarize(&frames);
11622 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011623 if (cursor + 4 > elements->length()) {
11624 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11625 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011627 for (int i = 0; i < cursor; i++) {
11628 new_elements->set(i, elements->get(i));
11629 }
11630 elements = new_elements;
11631 }
11632 ASSERT(cursor + 4 <= elements->length());
11633
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011634 Handle<Object> recv = frames[i].receiver();
11635 Handle<JSFunction> fun = frames[i].function();
11636 Handle<Code> code = frames[i].code();
11637 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011638 elements->set(cursor++, *recv);
11639 elements->set(cursor++, *fun);
11640 elements->set(cursor++, *code);
11641 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011642 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011643 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011644 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011645 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011647 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011648 return *result;
11649}
11650
11651
ager@chromium.org3811b432009-10-28 14:53:37 +000011652// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011654 ASSERT_EQ(args.length(), 0);
11655
11656 NoHandleAllocation ha;
11657
11658 const char* version_string = v8::V8::GetVersion();
11659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011660 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11661 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011662}
11663
11664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011665RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666 ASSERT(args.length() == 2);
11667 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11668 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670 OS::Abort();
11671 UNREACHABLE();
11672 return NULL;
11673}
11674
11675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011677 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011678 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011679 Object* key = args[1];
11680
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011681 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011682 Object* o = cache->get(finger_index);
11683 if (o == key) {
11684 // The fastest case: hit the same place again.
11685 return cache->get(finger_index + 1);
11686 }
11687
11688 for (int i = finger_index - 2;
11689 i >= JSFunctionResultCache::kEntriesIndex;
11690 i -= 2) {
11691 o = cache->get(i);
11692 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011693 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011694 return cache->get(i + 1);
11695 }
11696 }
11697
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011698 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011699 ASSERT(size <= cache->length());
11700
11701 for (int i = size - 2; i > finger_index; i -= 2) {
11702 o = cache->get(i);
11703 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011704 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011705 return cache->get(i + 1);
11706 }
11707 }
11708
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011709 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011711
11712 Handle<JSFunctionResultCache> cache_handle(cache);
11713 Handle<Object> key_handle(key);
11714 Handle<Object> value;
11715 {
11716 Handle<JSFunction> factory(JSFunction::cast(
11717 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11718 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011720 // This handle is nor shared, nor used later, so it's safe.
11721 Object** argv[] = { key_handle.location() };
11722 bool pending_exception = false;
11723 value = Execution::Call(factory,
11724 receiver,
11725 1,
11726 argv,
11727 &pending_exception);
11728 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011729 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011730
11731#ifdef DEBUG
11732 cache_handle->JSFunctionResultCacheVerify();
11733#endif
11734
11735 // Function invocation may have cleared the cache. Reread all the data.
11736 finger_index = cache_handle->finger_index();
11737 size = cache_handle->size();
11738
11739 // If we have spare room, put new data into it, otherwise evict post finger
11740 // entry which is likely to be the least recently used.
11741 int index = -1;
11742 if (size < cache_handle->length()) {
11743 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11744 index = size;
11745 } else {
11746 index = finger_index + JSFunctionResultCache::kEntrySize;
11747 if (index == cache_handle->length()) {
11748 index = JSFunctionResultCache::kEntriesIndex;
11749 }
11750 }
11751
11752 ASSERT(index % 2 == 0);
11753 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11754 ASSERT(index < cache_handle->length());
11755
11756 cache_handle->set(index, *key_handle);
11757 cache_handle->set(index + 1, *value);
11758 cache_handle->set_finger_index(index);
11759
11760#ifdef DEBUG
11761 cache_handle->JSFunctionResultCacheVerify();
11762#endif
11763
11764 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011765}
11766
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011768RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011770 CONVERT_ARG_CHECKED(String, type, 0);
11771 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011772 return *isolate->factory()->NewJSMessageObject(
11773 type,
11774 arguments,
11775 0,
11776 0,
11777 isolate->factory()->undefined_value(),
11778 isolate->factory()->undefined_value(),
11779 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011780}
11781
11782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011783RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011784 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11785 return message->type();
11786}
11787
11788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011789RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011790 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11791 return message->arguments();
11792}
11793
11794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011796 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11797 return Smi::FromInt(message->start_position());
11798}
11799
11800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011801RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011802 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11803 return message->script();
11804}
11805
11806
kasper.lund44510672008-07-25 07:37:58 +000011807#ifdef DEBUG
11808// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11809// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011810RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011811 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011812 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011813#define COUNT_ENTRY(Name, argc, ressize) + 1
11814 int entry_count = 0
11815 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11816 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11817 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11818#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011819 Factory* factory = isolate->factory();
11820 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011822 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011823#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 { \
11825 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011826 Handle<String> name; \
11827 /* Inline runtime functions have an underscore in front of the name. */ \
11828 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011829 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011830 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11831 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011833 Vector<const char>(#Name, StrLength(#Name))); \
11834 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011836 pair_elements->set(0, *name); \
11837 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011838 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011839 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011841 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011843 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011844 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011845 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011847 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849 return *result;
11850}
kasper.lund44510672008-07-25 07:37:58 +000011851#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852
11853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011854RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011855 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011856 CONVERT_CHECKED(String, format, args[0]);
11857 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011858 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011859 LOGGER->LogRuntime(chars, elms);
11860 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011861}
11862
11863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011864RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865 UNREACHABLE(); // implemented as macro in the parser
11866 return NULL;
11867}
11868
11869
11870// ----------------------------------------------------------------------------
11871// Implementation of Runtime
11872
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011873#define F(name, number_of_args, result_size) \
11874 { Runtime::k##name, Runtime::RUNTIME, #name, \
11875 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011877
11878#define I(name, number_of_args, result_size) \
11879 { Runtime::kInline##name, Runtime::INLINE, \
11880 "_" #name, NULL, number_of_args, result_size },
11881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011884 INLINE_FUNCTION_LIST(I)
11885 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886};
11887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11890 Object* dictionary) {
11891 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011892 ASSERT(dictionary != NULL);
11893 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11894 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011895 Object* name_symbol;
11896 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011897 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011898 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11899 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011900 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011901 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11902 String::cast(name_symbol),
11903 Smi::FromInt(i),
11904 PropertyDetails(NONE, NORMAL));
11905 if (!maybe_dictionary->ToObject(&dictionary)) {
11906 // Non-recoverable failure. Calling code must restart heap
11907 // initialization.
11908 return maybe_dictionary;
11909 }
11910 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011911 }
11912 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913}
11914
11915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011916const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11917 Heap* heap = name->GetHeap();
11918 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011919 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011921 int function_index = Smi::cast(smi_index)->value();
11922 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923 }
11924 return NULL;
11925}
11926
11927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011928const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011929 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11930}
11931
11932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011934 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011936 if (failure->IsRetryAfterGC()) {
11937 // Try to do a garbage collection; ignore it if it fails. The C
11938 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011939 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011940 } else {
11941 // Handle last resort GC and make sure to allow future allocations
11942 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011943 isolate->counters()->gc_last_resort_from_js()->Increment();
11944 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011945 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946}
11947
11948
11949} } // namespace v8::internal