blob: 363d7993eae4940b8642c38bd04e85554cc43953 [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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000227static MaybeObject* Runtime_CloneLiteralBoilerplate(
228 RUNTIME_CALLING_CONVENTION) {
229 RUNTIME_GET_ISOLATE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(
236 RUNTIME_CALLING_CONVENTION) {
237 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240}
241
242
ager@chromium.org236ad962008-09-25 09:45:57 +0000243static Handle<Map> ComputeObjectLiteralMap(
244 Handle<Context> context,
245 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000246 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 int properties_length = constant_properties->length();
249 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000252 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000253 for (int p = 0; p != properties_length; p += 2) {
254 Object* key = constant_properties->get(p);
255 uint32_t element_index = 0;
256 if (key->IsSymbol()) {
257 number_of_symbol_keys++;
258 } else if (key->ToArrayIndex(&element_index)) {
259 // An index key does not require space in the property backing store.
260 number_of_properties--;
261 } else {
262 // Bail out as a non-symbol non-index key makes caching impossible.
263 // ASSERT to make sure that the if condition after the loop is false.
264 ASSERT(number_of_symbol_keys != number_of_properties);
265 break;
266 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // If we only have symbols and array indices among keys then we can
269 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000271 if ((number_of_symbol_keys == number_of_properties) &&
272 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000273 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Handle<FixedArray> keys =
275 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000276 if (number_of_symbol_keys > 0) {
277 int index = 0;
278 for (int p = 0; p < properties_length; p += 2) {
279 Object* key = constant_properties->get(p);
280 if (key->IsSymbol()) {
281 keys->set(index++, key);
282 }
283 }
284 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000288 }
289 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000290 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000292 Handle<Map>(context->object_function()->initial_map()),
293 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000294}
295
296
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299 Handle<FixedArray> literals,
300 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000301
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302
303static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000305 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000306 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000307 bool should_have_fast_elements,
308 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000309 // Get the global context from the literals array. This is the
310 // context in which the function was created and we use the object
311 // function from this context to create the object literal. We do
312 // not use the object function from the current global context
313 // because this might be the object function from another context
314 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 Handle<Context> context =
316 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 // In case we have function literals, we want the object to be in
319 // slow properties mode for now. We don't go in the map cache because
320 // maps with constant functions can't be shared if the functions are
321 // not the same (which is the common case).
322 bool is_result_from_cache = false;
323 Handle<Map> map = has_function_literal
324 ? Handle<Map>(context->object_function()->initial_map())
325 : ComputeObjectLiteralMap(context,
326 constant_properties,
327 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000330
331 // Normalize the elements of the boilerplate to save space if needed.
332 if (!should_have_fast_elements) NormalizeElements(boilerplate);
333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 // Add the constant properties to the boilerplate.
335 int length = constant_properties->length();
336 bool should_transform =
337 !is_result_from_cache && boilerplate->HasFastProperties();
338 if (should_transform || has_function_literal) {
339 // Normalize the properties of object to avoid n^2 behavior
340 // when extending the object multiple properties. Indicate the number of
341 // properties to be added.
342 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
343 }
344
345 for (int index = 0; index < length; index +=2) {
346 Handle<Object> key(constant_properties->get(index+0), isolate);
347 Handle<Object> value(constant_properties->get(index+1), isolate);
348 if (value->IsFixedArray()) {
349 // The value contains the constant_properties of a
350 // simple object or array literal.
351 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
352 value = CreateLiteralBoilerplate(isolate, literals, array);
353 if (value.is_null()) return value;
354 }
355 Handle<Object> result;
356 uint32_t element_index = 0;
357 if (key->IsSymbol()) {
358 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
359 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000360 result = SetOwnElement(boilerplate,
361 element_index,
362 value,
363 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 Handle<String> name(String::cast(*key));
366 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000367 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
368 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 } else if (key->ToArrayIndex(&element_index)) {
371 // Array index (uint32).
372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
376 } else {
377 // Non-uint32 number.
378 ASSERT(key->IsNumber());
379 double num = key->Number();
380 char arr[100];
381 Vector<char> buffer(arr, ARRAY_SIZE(arr));
382 const char* str = DoubleToCString(num, buffer);
383 Handle<String> name =
384 isolate->factory()->NewStringFromAscii(CStrVector(str));
385 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
386 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000388 // If setting the property on the boilerplate throws an
389 // exception, the exception is converted to an empty handle in
390 // the handle based operations. In that case, we need to
391 // convert back to an exception.
392 if (result.is_null()) return result;
393 }
394
395 // Transform to fast properties if necessary. For object literals with
396 // containing function literals we defer this operation until after all
397 // computed properties have been assigned so that we can generate
398 // constant function properties.
399 if (should_transform && !has_function_literal) {
400 TransformToFastProperties(boilerplate,
401 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 }
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000405}
406
407
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000410 Handle<FixedArray> literals,
411 Handle<FixedArray> elements) {
412 // Create the JSArray.
413 Handle<JSFunction> constructor(
414 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 const bool is_cow =
418 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421
422 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000423 if (is_cow) {
424#ifdef DEBUG
425 // Copy-on-write arrays must be shallow (and simple).
426 for (int i = 0; i < content->length(); i++) {
427 ASSERT(!content->get(i)->IsFixedArray());
428 }
429#endif
430 } else {
431 for (int i = 0; i < content->length(); i++) {
432 if (content->get(i)->IsFixedArray()) {
433 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
436 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000438 if (result.is_null()) return result;
439 content->set(i, *result);
440 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 }
442 }
443
444 // Set the elements.
445 Handle<JSArray>::cast(object)->SetContent(*content);
446 return object;
447}
448
449
450static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 Handle<FixedArray> literals,
453 Handle<FixedArray> array) {
454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000456 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 return CreateObjectLiteralBoilerplate(isolate,
459 literals,
460 elements,
461 true,
462 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 return CreateObjectLiteralBoilerplate(isolate,
465 literals,
466 elements,
467 false,
468 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000471 default:
472 UNREACHABLE();
473 return Handle<Object>::null();
474 }
475}
476
477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000478static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(
479 RUNTIME_CALLING_CONVENTION) {
480 RUNTIME_GET_ISOLATE;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000481 // Takes a FixedArray of elements containing the literal elements of
482 // the array literal and produces JSArray with those elements.
483 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000484 // which contains the context from which to get the Array function
485 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487 ASSERT(args.length() == 3);
488 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
489 CONVERT_SMI_CHECKED(literals_index, args[1]);
490 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000492 Handle<Object> object =
493 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000494 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 // Update the functions literal and return the boilerplate.
497 literals->set(literals_index, *object);
498 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499}
500
501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) {
503 RUNTIME_GET_ISOLATE;
504 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000505 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
507 CONVERT_SMI_CHECKED(literals_index, args[1]);
508 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 CONVERT_SMI_CHECKED(flags, args[3]);
510 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
511 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000512
513 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 Handle<Object> boilerplate(literals->get(literals_index), isolate);
515 if (*boilerplate == isolate->heap()->undefined_value()) {
516 boilerplate = CreateObjectLiteralBoilerplate(isolate,
517 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000518 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 should_have_fast_elements,
520 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521 if (boilerplate.is_null()) return Failure::Exception();
522 // Update the functions literal and return the boilerplate.
523 literals->set(literals_index, *boilerplate);
524 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526}
527
528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529static MaybeObject* Runtime_CreateObjectLiteralShallow(
530 RUNTIME_CALLING_CONVENTION) {
531 RUNTIME_GET_ISOLATE;
532 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
535 CONVERT_SMI_CHECKED(literals_index, args[1]);
536 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 CONVERT_SMI_CHECKED(flags, args[3]);
538 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
539 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540
541 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 Handle<Object> boilerplate(literals->get(literals_index), isolate);
543 if (*boilerplate == isolate->heap()->undefined_value()) {
544 boilerplate = CreateObjectLiteralBoilerplate(isolate,
545 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000546 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 should_have_fast_elements,
548 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000549 if (boilerplate.is_null()) return Failure::Exception();
550 // Update the functions literal and return the boilerplate.
551 literals->set(literals_index, *boilerplate);
552 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554}
555
556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557static MaybeObject* Runtime_CreateArrayLiteral(RUNTIME_CALLING_CONVENTION) {
558 RUNTIME_GET_ISOLATE;
559 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 ASSERT(args.length() == 3);
561 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
562 CONVERT_SMI_CHECKED(literals_index, args[1]);
563 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
564
565 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 Handle<Object> boilerplate(literals->get(literals_index), isolate);
567 if (*boilerplate == isolate->heap()->undefined_value()) {
568 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 if (boilerplate.is_null()) return Failure::Exception();
570 // Update the functions literal and return the boilerplate.
571 literals->set(literals_index, *boilerplate);
572 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574}
575
576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577static MaybeObject* Runtime_CreateArrayLiteralShallow(
578 RUNTIME_CALLING_CONVENTION) {
579 RUNTIME_GET_ISOLATE;
580 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 ASSERT(args.length() == 3);
582 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
583 CONVERT_SMI_CHECKED(literals_index, args[1]);
584 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
585
586 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 Handle<Object> boilerplate(literals->get(literals_index), isolate);
588 if (*boilerplate == isolate->heap()->undefined_value()) {
589 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590 if (boilerplate.is_null()) return Failure::Exception();
591 // Update the functions literal and return the boilerplate.
592 literals->set(literals_index, *boilerplate);
593 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000594 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 isolate->heap()->fixed_cow_array_map()) {
596 COUNTERS->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599}
600
601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602static MaybeObject* Runtime_CreateCatchExtensionObject(
603 RUNTIME_CALLING_CONVENTION) {
604 RUNTIME_GET_ISOLATE;
ager@chromium.org32912102009-01-16 10:38:43 +0000605 ASSERT(args.length() == 2);
606 CONVERT_CHECKED(String, key, args[0]);
607 Object* value = args[1];
608 // Create a catch context extension object.
609 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 isolate->context()->global_context()->
611 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 if (!maybe_object->ToObject(&object)) return maybe_object;
615 }
ager@chromium.org32912102009-01-16 10:38:43 +0000616 // Assign the exception value to the catch variable and make sure
617 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000618 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
620 JSObject::cast(object)->SetProperty(
621 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000622 if (!maybe_value->ToObject(&value)) return maybe_value;
623 }
ager@chromium.org32912102009-01-16 10:38:43 +0000624 return object;
625}
626
627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628static MaybeObject* Runtime_ClassOf(RUNTIME_CALLING_CONVENTION) {
629 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 NoHandleAllocation ha;
631 ASSERT(args.length() == 1);
632 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 return JSObject::cast(obj)->class_name();
635}
636
ager@chromium.org7c537e22008-10-16 08:43:32 +0000637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638static MaybeObject* Runtime_IsInPrototypeChain(RUNTIME_CALLING_CONVENTION) {
639 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000655static MaybeObject* Runtime_SetHiddenPrototype(RUNTIME_CALLING_CONVENTION) {
656 RUNTIME_GET_ISOLATE;
ager@chromium.org9085a012009-05-11 19:22:57 +0000657 NoHandleAllocation ha;
658 ASSERT(args.length() == 2);
659 CONVERT_CHECKED(JSObject, jsobject, args[0]);
660 CONVERT_CHECKED(JSObject, proto, args[1]);
661
662 // Sanity checks. The old prototype (that we are replacing) could
663 // theoretically be null, but if it is not null then check that we
664 // didn't already install a hidden prototype here.
665 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
666 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
667 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
668
669 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000670 Object* map_or_failure;
671 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
672 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
673 return maybe_map_or_failure;
674 }
675 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 Map* new_proto_map = Map::cast(map_or_failure);
677
lrn@chromium.org303ada72010-10-27 09:33:13 +0000678 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
679 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
680 return maybe_map_or_failure;
681 }
682 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000683 Map* new_map = Map::cast(map_or_failure);
684
685 // Set proto's prototype to be the old prototype of the object.
686 new_proto_map->set_prototype(jsobject->GetPrototype());
687 proto->set_map(new_proto_map);
688 new_proto_map->set_is_hidden_prototype();
689
690 // Set the object's prototype to proto.
691 new_map->set_prototype(proto);
692 jsobject->set_map(new_map);
693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000694 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000695}
696
697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
699 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000701 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 JavaScriptFrameIterator it;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704}
705
706
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000707// Recursively traverses hidden prototypes if property is not found
708static void GetOwnPropertyImplementation(JSObject* obj,
709 String* name,
710 LookupResult* result) {
711 obj->LocalLookupRealNamedProperty(name, result);
712
713 if (!result->IsProperty()) {
714 Object* proto = obj->GetPrototype();
715 if (proto->IsJSObject() &&
716 JSObject::cast(proto)->map()->is_hidden_prototype())
717 GetOwnPropertyImplementation(JSObject::cast(proto),
718 name, result);
719 }
720}
721
722
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000723static bool CheckAccessException(LookupResult* result,
724 v8::AccessType access_type) {
725 if (result->type() == CALLBACKS) {
726 Object* callback = result->GetCallbackObject();
727 if (callback->IsAccessorInfo()) {
728 AccessorInfo* info = AccessorInfo::cast(callback);
729 bool can_access =
730 (access_type == v8::ACCESS_HAS &&
731 (info->all_can_read() || info->all_can_write())) ||
732 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
733 (access_type == v8::ACCESS_SET && info->all_can_write());
734 return can_access;
735 }
736 }
737
738 return false;
739}
740
741
742static bool CheckAccess(JSObject* obj,
743 String* name,
744 LookupResult* result,
745 v8::AccessType access_type) {
746 ASSERT(result->IsProperty());
747
748 JSObject* holder = result->holder();
749 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000750 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000751 while (true) {
752 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000753 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000754 // Access check callback denied the access, but some properties
755 // can have a special permissions which override callbacks descision
756 // (currently see v8::AccessControl).
757 break;
758 }
759
760 if (current == holder) {
761 return true;
762 }
763
764 current = JSObject::cast(current->GetPrototype());
765 }
766
767 // API callbacks can have per callback access exceptions.
768 switch (result->type()) {
769 case CALLBACKS: {
770 if (CheckAccessException(result, access_type)) {
771 return true;
772 }
773 break;
774 }
775 case INTERCEPTOR: {
776 // If the object has an interceptor, try real named properties.
777 // Overwrite the result to fetch the correct property later.
778 holder->LookupRealNamedProperty(name, result);
779 if (result->IsProperty()) {
780 if (CheckAccessException(result, access_type)) {
781 return true;
782 }
783 }
784 break;
785 }
786 default:
787 break;
788 }
789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000790 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000791 return false;
792}
793
794
795// TODO(1095): we should traverse hidden prototype hierachy as well.
796static bool CheckElementAccess(JSObject* obj,
797 uint32_t index,
798 v8::AccessType access_type) {
799 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000801 return false;
802 }
803
804 return true;
805}
806
807
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000808// Enumerator used as indices into the array returned from GetOwnProperty
809enum PropertyDescriptorIndices {
810 IS_ACCESSOR_INDEX,
811 VALUE_INDEX,
812 GETTER_INDEX,
813 SETTER_INDEX,
814 WRITABLE_INDEX,
815 ENUMERABLE_INDEX,
816 CONFIGURABLE_INDEX,
817 DESCRIPTOR_SIZE
818};
819
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000820// Returns an array with the property description:
821// if args[1] is not a property on args[0]
822// returns undefined
823// if args[1] is a data property on args[0]
824// [false, value, Writeable, Enumerable, Configurable]
825// if args[1] is an accessor on args[0]
826// [true, GetFunction, SetFunction, Enumerable, Configurable]
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827static MaybeObject* Runtime_GetOwnProperty(RUNTIME_CALLING_CONVENTION) {
828 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000829 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 Heap* heap = isolate->heap();
831 HandleScope scope(isolate);
832 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
833 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000835 CONVERT_ARG_CHECKED(JSObject, obj, 0);
836 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000837
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000838 // This could be an element.
839 uint32_t index;
840 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 switch (obj->HasLocalElement(index)) {
842 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000844
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000845 case JSObject::STRING_CHARACTER_ELEMENT: {
846 // Special handling of string objects according to ECMAScript 5
847 // 15.5.5.2. Note that this might be a string object with elements
848 // other than the actual string value. This is covered by the
849 // subsequent cases.
850 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
851 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000852 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000855 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 elms->set(WRITABLE_INDEX, heap->false_value());
857 elms->set(ENUMERABLE_INDEX, heap->false_value());
858 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000859 return *desc;
860 }
861
862 case JSObject::INTERCEPTED_ELEMENT:
863 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000865 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000866 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000867 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 elms->set(WRITABLE_INDEX, heap->true_value());
869 elms->set(ENUMERABLE_INDEX, heap->true_value());
870 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000871 return *desc;
872 }
873
874 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000875 Handle<JSObject> holder = obj;
876 if (obj->IsJSGlobalProxy()) {
877 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000879 ASSERT(proto->IsJSGlobalObject());
880 holder = Handle<JSObject>(JSObject::cast(proto));
881 }
882 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000883 int entry = dictionary->FindEntry(index);
884 ASSERT(entry != NumberDictionary::kNotFound);
885 PropertyDetails details = dictionary->DetailsAt(entry);
886 switch (details.type()) {
887 case CALLBACKS: {
888 // This is an accessor property with getter and/or setter.
889 FixedArray* callbacks =
890 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000891 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
893 elms->set(GETTER_INDEX, callbacks->get(0));
894 }
895 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
896 elms->set(SETTER_INDEX, callbacks->get(1));
897 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 break;
899 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000904 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000905 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000907 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 default:
910 UNREACHABLE();
911 break;
912 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
914 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000915 return *desc;
916 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917 }
918 }
919
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000920 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000922
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000923 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000925 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000926
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000927 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 }
930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
932 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000933
934 bool is_js_accessor = (result.type() == CALLBACKS) &&
935 (result.GetCallbackObject()->IsFixedArray());
936
937 if (is_js_accessor) {
938 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000940
941 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
942 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
943 elms->set(GETTER_INDEX, structure->get(0));
944 }
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
946 elms->set(SETTER_INDEX, structure->get(1));
947 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000948 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
950 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951
952 PropertyAttributes attrs;
953 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000954 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
956 if (!maybe_value->ToObject(&value)) return maybe_value;
957 }
958 elms->set(VALUE_INDEX, value);
959 }
960
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000961 return *desc;
962}
963
964
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965static MaybeObject* Runtime_PreventExtensions(RUNTIME_CALLING_CONVENTION) {
966 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000967 ASSERT(args.length() == 1);
968 CONVERT_CHECKED(JSObject, obj, args[0]);
969 return obj->PreventExtensions();
970}
971
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973static MaybeObject* Runtime_IsExtensible(RUNTIME_CALLING_CONVENTION) {
974 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000975 ASSERT(args.length() == 1);
976 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000977 if (obj->IsJSGlobalProxy()) {
978 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000980 ASSERT(proto->IsJSGlobalObject());
981 obj = JSObject::cast(proto);
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return obj->map()->is_extensible() ? isolate->heap()->true_value()
984 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000985}
986
987
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000988static MaybeObject* Runtime_RegExpCompile(RUNTIME_CALLING_CONVENTION) {
989 RUNTIME_GET_ISOLATE;
990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001static MaybeObject* Runtime_CreateApiFunction(RUNTIME_CALLING_CONVENTION) {
1002 RUNTIME_GET_ISOLATE;
1003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001005 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010static MaybeObject* Runtime_IsTemplate(RUNTIME_CALLING_CONVENTION) {
1011 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 ASSERT(args.length() == 1);
1013 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001014 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016}
1017
1018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019static MaybeObject* Runtime_GetTemplateField(RUNTIME_CALLING_CONVENTION) {
1020 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 ASSERT(args.length() == 2);
1022 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001024 int index = field->value();
1025 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1026 InstanceType type = templ->map()->instance_type();
1027 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1028 type == OBJECT_TEMPLATE_INFO_TYPE);
1029 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001030 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001031 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1032 } else {
1033 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1034 }
1035 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036}
1037
1038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039static MaybeObject* Runtime_DisableAccessChecks(RUNTIME_CALLING_CONVENTION) {
1040 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00001041 ASSERT(args.length() == 1);
1042 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001043 Map* old_map = object->map();
1044 bool needs_access_checks = old_map->is_access_check_needed();
1045 if (needs_access_checks) {
1046 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001047 Object* new_map;
1048 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1049 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1050 }
ager@chromium.org32912102009-01-16 10:38:43 +00001051
1052 Map::cast(new_map)->set_is_access_check_needed(false);
1053 object->set_map(Map::cast(new_map));
1054 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 return needs_access_checks ? isolate->heap()->true_value()
1056 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057}
1058
1059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060static MaybeObject* Runtime_EnableAccessChecks(RUNTIME_CALLING_CONVENTION) {
1061 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00001062 ASSERT(args.length() == 1);
1063 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001064 Map* old_map = object->map();
1065 if (!old_map->is_access_check_needed()) {
1066 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001067 Object* new_map;
1068 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1069 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1070 }
ager@chromium.org32912102009-01-16 10:38:43 +00001071
1072 Map::cast(new_map)->set_is_access_check_needed(true);
1073 object->set_map(Map::cast(new_map));
1074 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001076}
1077
1078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079static Failure* ThrowRedeclarationError(Isolate* isolate,
1080 const char* type,
1081 Handle<String> name) {
1082 HandleScope scope(isolate);
1083 Handle<Object> type_handle =
1084 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 Handle<Object> args[2] = { type_handle, name };
1086 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1088 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089}
1090
1091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001092static MaybeObject* Runtime_DeclareGlobals(RUNTIME_CALLING_CONVENTION) {
1093 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001094 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 HandleScope scope(isolate);
1096 Handle<GlobalObject> global = Handle<GlobalObject>(
1097 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
ager@chromium.org3811b432009-10-28 14:53:37 +00001099 Handle<Context> context = args.at<Context>(0);
1100 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001102 StrictModeFlag strict_mode =
1103 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1104 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105
1106 // Compute the property attributes. According to ECMA-262, section
1107 // 13, page 71, the property must be read-only and
1108 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1109 // property as read-only, so we don't either.
1110 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 // Traverse the name/value pairs and set the properties.
1113 int length = pairs->length();
1114 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001115 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001117 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // We have to declare a global const property. To capture we only
1120 // assign to it when evaluating the assignment for "const x =
1121 // <expr>" the initial value is the hole.
1122 bool is_const_property = value->IsTheHole();
1123
1124 if (value->IsUndefined() || is_const_property) {
1125 // Lookup the property in the global object, and don't set the
1126 // value of the variable if the property is already there.
1127 LookupResult lookup;
1128 global->Lookup(*name, &lookup);
1129 if (lookup.IsProperty()) {
1130 // Determine if the property is local by comparing the holder
1131 // against the global object. The information will be used to
1132 // avoid throwing re-declaration errors when declaring
1133 // variables or constants that exist in the prototype chain.
1134 bool is_local = (*global == lookup.holder());
1135 // Get the property attributes and determine if the property is
1136 // read-only.
1137 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1138 bool is_read_only = (attributes & READ_ONLY) != 0;
1139 if (lookup.type() == INTERCEPTOR) {
1140 // If the interceptor says the property is there, we
1141 // just return undefined without overwriting the property.
1142 // Otherwise, we continue to setting the property.
1143 if (attributes != ABSENT) {
1144 // Check if the existing property conflicts with regards to const.
1145 if (is_local && (is_read_only || is_const_property)) {
1146 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 };
1149 // The property already exists without conflicting: Go to
1150 // the next declaration.
1151 continue;
1152 }
1153 // Fall-through and introduce the absent property by using
1154 // SetProperty.
1155 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001156 // For const properties, we treat a callback with this name
1157 // even in the prototype as a conflicting declaration.
1158 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001160 }
1161 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 if (is_local && (is_read_only || is_const_property)) {
1163 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 }
1166 // The property already exists without conflicting: Go to
1167 // the next declaration.
1168 continue;
1169 }
1170 }
1171 } else {
1172 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001173 Handle<SharedFunctionInfo> shared =
1174 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001176 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1177 context,
1178 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 value = function;
1180 }
1181
1182 LookupResult lookup;
1183 global->LocalLookup(*name, &lookup);
1184
1185 PropertyAttributes attributes = is_const_property
1186 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1187 : base;
1188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001189 // There's a local property that we need to overwrite because
1190 // we're either declaring a function or there's an interceptor
1191 // that claims the property is absent.
1192 //
1193 // Check for conflicting re-declarations. We cannot have
1194 // conflicting types in case of intercepted properties because
1195 // they are absent.
1196 if (lookup.IsProperty() &&
1197 (lookup.type() != INTERCEPTOR) &&
1198 (lookup.IsReadOnly() || is_const_property)) {
1199 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 // Safari does not allow the invocation of callback setters for
1204 // function declarations. To mimic this behavior, we do not allow
1205 // the invocation of setters for function values. This makes a
1206 // difference for global functions with the same names as event
1207 // handlers such as "function onload() {}". Firefox does call the
1208 // onload setter in those case and Safari does not. We follow
1209 // Safari for compatibility.
1210 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001211 // Do not change DONT_DELETE to false from true.
1212 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1213 attributes = static_cast<PropertyAttributes>(
1214 attributes | (lookup.GetAttributes() & DONT_DELETE));
1215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 RETURN_IF_EMPTY_HANDLE(isolate,
1217 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001218 name,
1219 value,
1220 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001222 RETURN_IF_EMPTY_HANDLE(isolate,
1223 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 name,
1225 value,
1226 attributes,
1227 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 }
1229 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 ASSERT(!isolate->has_pending_exception());
1232 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233}
1234
1235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236static MaybeObject* Runtime_DeclareContextSlot(RUNTIME_CALLING_CONVENTION) {
1237 RUNTIME_GET_ISOLATE;
1238 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001239 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240
ager@chromium.org7c537e22008-10-16 08:43:32 +00001241 CONVERT_ARG_CHECKED(Context, context, 0);
1242 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001244 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001245 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
1248 // Declarations are always done in the function context.
1249 context = Handle<Context>(context->fcontext());
1250
1251 int index;
1252 PropertyAttributes attributes;
1253 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001254 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 context->Lookup(name, flags, &index, &attributes);
1256
1257 if (attributes != ABSENT) {
1258 // The name was declared before; check for conflicting
1259 // re-declarations: This is similar to the code in parser.cc in
1260 // the AstBuildingParser::Declare function.
1261 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1262 // Functions are not read-only.
1263 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1264 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 }
1267
1268 // Initialize it if necessary.
1269 if (*initial_value != NULL) {
1270 if (index >= 0) {
1271 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001272 // the function context or the arguments object.
1273 if (holder->IsContext()) {
1274 ASSERT(holder.is_identical_to(context));
1275 if (((attributes & READ_ONLY) == 0) ||
1276 context->get(index)->IsTheHole()) {
1277 context->set(index, *initial_value);
1278 }
1279 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001280 // The holder is an arguments object.
1281 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001282 Handle<Object> result = SetElement(arguments, index, initial_value,
1283 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001284 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 } else {
1287 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001288 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001289 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 SetProperty(context_ext, name, initial_value,
1292 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 }
1294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001297 // The property is not in the function context. It needs to be
1298 // "declared" in the function context's extension context, or in the
1299 // global context.
1300 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001301 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 // The function context's extension context exists - use it.
1303 context_ext = Handle<JSObject>(context->extension());
1304 } else {
1305 // The function context's extension context does not exists - allocate
1306 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 context_ext = isolate->factory()->NewJSObject(
1308 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 // And store it in the extension slot.
1310 context->set_extension(*context_ext);
1311 }
1312 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313
ager@chromium.org7c537e22008-10-16 08:43:32 +00001314 // Declare the property by setting it to the initial value if provided,
1315 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1316 // constant declarations).
1317 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001319 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Declaring a const context slot is a conflicting declaration if
1321 // there is a callback with that name in a prototype. It is
1322 // allowed to introduce const variables in
1323 // JSContextExtensionObjects. They are treated specially in
1324 // SetProperty and no setters are invoked for those since they are
1325 // not real JSObjects.
1326 if (initial_value->IsTheHole() &&
1327 !context_ext->IsJSContextExtensionObject()) {
1328 LookupResult lookup;
1329 context_ext->Lookup(*name, &lookup);
1330 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 }
1333 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001334 RETURN_IF_EMPTY_HANDLE(isolate,
1335 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 }
1338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001339 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340}
1341
1342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001343static MaybeObject* Runtime_InitializeVarGlobal(RUNTIME_CALLING_CONVENTION) {
1344 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001346 // args[0] == name
1347 // args[1] == strict_mode
1348 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349
1350 // Determine if we need to assign to the variable if it already
1351 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001352 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1353 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354
1355 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001357 RUNTIME_ASSERT(args[1]->IsSmi());
1358 StrictModeFlag strict_mode =
1359 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1360 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361
1362 // According to ECMA-262, section 12.2, page 62, the property must
1363 // not be deletable.
1364 PropertyAttributes attributes = DONT_DELETE;
1365
1366 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001367 // there, there is a property with this name in the prototype chain.
1368 // We follow Safari and Firefox behavior and only set the property
1369 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001370 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001371 // Note that objects can have hidden prototypes, so we need to traverse
1372 // the whole chain of hidden prototypes to do a 'local' lookup.
1373 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001375 while (true) {
1376 real_holder->LocalLookup(*name, &lookup);
1377 if (lookup.IsProperty()) {
1378 // Determine if this is a redeclaration of something read-only.
1379 if (lookup.IsReadOnly()) {
1380 // If we found readonly property on one of hidden prototypes,
1381 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 if (real_holder != isolate->context()->global()) break;
1383 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 }
1385
1386 // Determine if this is a redeclaration of an intercepted read-only
1387 // property and figure out if the property exists at all.
1388 bool found = true;
1389 PropertyType type = lookup.type();
1390 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001391 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001392 Handle<JSObject> holder(real_holder);
1393 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1394 real_holder = *holder;
1395 if (intercepted == ABSENT) {
1396 // The interceptor claims the property isn't there. We need to
1397 // make sure to introduce it.
1398 found = false;
1399 } else if ((intercepted & READ_ONLY) != 0) {
1400 // The property is present, but read-only. Since we're trying to
1401 // overwrite it with a variable declaration we must throw a
1402 // re-declaration error. However if we found readonly property
1403 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 if (real_holder != isolate->context()->global()) break;
1405 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001406 }
1407 }
1408
1409 if (found && !assign) {
1410 // The global property is there and we're not assigning any value
1411 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001413 }
1414
1415 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001417 return real_holder->SetProperty(
1418 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001419 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001420
1421 Object* proto = real_holder->GetPrototype();
1422 if (!proto->IsJSObject())
1423 break;
1424
1425 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1426 break;
1427
1428 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 }
1430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432 if (assign) {
1433 return global->SetProperty(*name, args[2], attributes, strict_mode);
1434 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436}
1437
1438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001439static MaybeObject* Runtime_InitializeConstGlobal(RUNTIME_CALLING_CONVENTION) {
1440 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 // All constants are declared with an initial value. The name
1442 // of the constant is the first argument and the initial value
1443 // is the second.
1444 RUNTIME_ASSERT(args.length() == 2);
1445 CONVERT_ARG_CHECKED(String, name, 0);
1446 Handle<Object> value = args.at<Object>(1);
1447
1448 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001449 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450
1451 // According to ECMA-262, section 12.2, page 62, the property must
1452 // not be deletable. Since it's a const, it must be READ_ONLY too.
1453 PropertyAttributes attributes =
1454 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1455
1456 // Lookup the property locally in the global object. If it isn't
1457 // there, we add the property and take special precautions to always
1458 // add it as a local property even in case of callbacks in the
1459 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001460 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 LookupResult lookup;
1462 global->LocalLookup(*name, &lookup);
1463 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001464 return global->SetLocalPropertyIgnoreAttributes(*name,
1465 *value,
1466 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 }
1468
1469 // Determine if this is a redeclaration of something not
1470 // read-only. In case the result is hidden behind an interceptor we
1471 // need to ask it for the property attributes.
1472 if (!lookup.IsReadOnly()) {
1473 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 }
1476
1477 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1478
1479 // Throw re-declaration error if the intercepted property is present
1480 // but not read-only.
1481 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484
1485 // Restore global object from context (in case of GC) and continue
1486 // with setting the value because the property is either absent or
1487 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 HandleScope handle_scope(isolate);
1489 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001491 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492 // property through an interceptor and only do it if it's
1493 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001494 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 RETURN_IF_EMPTY_HANDLE(isolate,
1496 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001497 name,
1498 value,
1499 attributes,
1500 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 return *value;
1502 }
1503
1504 // Set the value, but only we're assigning the initial value to a
1505 // constant. For now, we determine this by checking if the
1506 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 PropertyType type = lookup.type();
1509 if (type == FIELD) {
1510 FixedArray* properties = global->properties();
1511 int index = lookup.GetFieldIndex();
1512 if (properties->get(index)->IsTheHole()) {
1513 properties->set(index, *value);
1514 }
1515 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001516 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1517 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 }
1519 } else {
1520 // Ignore re-initialization of constants that have already been
1521 // assigned a function value.
1522 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1523 }
1524
1525 // Use the set value as the result of the operation.
1526 return *value;
1527}
1528
1529
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530static MaybeObject* Runtime_InitializeConstContextSlot(
1531 RUNTIME_CALLING_CONVENTION) {
1532 RUNTIME_GET_ISOLATE;
1533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 ASSERT(args.length() == 3);
1535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001536 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537 ASSERT(!value->IsTheHole());
1538 CONVERT_ARG_CHECKED(Context, context, 1);
1539 Handle<String> name(String::cast(args[2]));
1540
1541 // Initializations are always done in the function context.
1542 context = Handle<Context>(context->fcontext());
1543
1544 int index;
1545 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001546 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001547 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 context->Lookup(name, flags, &index, &attributes);
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // In most situations, the property introduced by the const
1551 // declaration should be present in the context extension object.
1552 // However, because declaration and initialization are separate, the
1553 // property might have been deleted (if it was introduced by eval)
1554 // before we reach the initialization point.
1555 //
1556 // Example:
1557 //
1558 // function f() { eval("delete x; const x;"); }
1559 //
1560 // In that case, the initialization behaves like a normal assignment
1561 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // Property was found in a context.
1564 if (holder->IsContext()) {
1565 // The holder cannot be the function context. If it is, there
1566 // should have been a const redeclaration error when declaring
1567 // the const property.
1568 ASSERT(!holder.is_identical_to(context));
1569 if ((attributes & READ_ONLY) == 0) {
1570 Handle<Context>::cast(holder)->set(index, *value);
1571 }
1572 } else {
1573 // The holder is an arguments object.
1574 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001575 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001576 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001578 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 }
1580 return *value;
1581 }
1582
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001583 // The property could not be found, we introduce it in the global
1584 // context.
1585 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001586 Handle<JSObject> global = Handle<JSObject>(
1587 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001588 // Strict mode not needed (const disallowed in strict mode).
1589 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001591 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 return *value;
1593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001595 // The property was present in a context extension object.
1596 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001598 if (*context_ext == context->extension()) {
1599 // This is the property that was introduced by the const
1600 // declaration. Set it if it hasn't been set before. NOTE: We
1601 // cannot use GetProperty() to get the current value as it
1602 // 'unholes' the value.
1603 LookupResult lookup;
1604 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1605 ASSERT(lookup.IsProperty()); // the property was declared
1606 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1607
1608 PropertyType type = lookup.type();
1609 if (type == FIELD) {
1610 FixedArray* properties = context_ext->properties();
1611 int index = lookup.GetFieldIndex();
1612 if (properties->get(index)->IsTheHole()) {
1613 properties->set(index, *value);
1614 }
1615 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001616 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1617 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001618 }
1619 } else {
1620 // We should not reach here. Any real, named property should be
1621 // either a field or a dictionary slot.
1622 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 }
1624 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001625 // The property was found in a different context extension object.
1626 // Set it if it is not a read-only property.
1627 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001628 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001629 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001630 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001631 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 return *value;
1636}
1637
1638
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 RUNTIME_CALLING_CONVENTION) {
1641 RUNTIME_GET_ISOLATE;
1642 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001643 ASSERT(args.length() == 2);
1644 CONVERT_ARG_CHECKED(JSObject, object, 0);
1645 CONVERT_SMI_CHECKED(properties, args[1]);
1646 if (object->HasFastProperties()) {
1647 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1648 }
1649 return *object;
1650}
1651
1652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653static MaybeObject* Runtime_RegExpExec(RUNTIME_CALLING_CONVENTION) {
1654 RUNTIME_GET_ISOLATE;
1655 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001656 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001657 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1658 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001659 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001660 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001661 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001662 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001663 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001664 RUNTIME_ASSERT(index >= 0);
1665 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001667 Handle<Object> result = RegExpImpl::Exec(regexp,
1668 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001669 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001670 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001671 if (result.is_null()) return Failure::Exception();
1672 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673}
1674
1675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676static MaybeObject* Runtime_RegExpConstructResult(RUNTIME_CALLING_CONVENTION) {
1677 RUNTIME_GET_ISOLATE;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001678 ASSERT(args.length() == 3);
1679 CONVERT_SMI_CHECKED(elements_count, args[0]);
1680 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001683 Object* new_object;
1684 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001686 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1687 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001688 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1690 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1692 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001693 {
1694 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001696 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001698 }
1699 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 array->set_elements(elements);
1702 array->set_length(Smi::FromInt(elements_count));
1703 // Write in-object properties after the length of the array.
1704 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1705 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1706 return array;
1707}
1708
1709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710static MaybeObject* Runtime_RegExpInitializeObject(RUNTIME_CALLING_CONVENTION) {
1711 RUNTIME_GET_ISOLATE;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001712 AssertNoAllocation no_alloc;
1713 ASSERT(args.length() == 5);
1714 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1715 CONVERT_CHECKED(String, source, args[1]);
1716
1717 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001719
1720 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001722
1723 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001725
1726 Map* map = regexp->map();
1727 Object* constructor = map->constructor();
1728 if (constructor->IsJSFunction() &&
1729 JSFunction::cast(constructor)->initial_map() == map) {
1730 // If we still have the original map, set in-object properties directly.
1731 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1732 // TODO(lrn): Consider skipping write barrier on booleans as well.
1733 // Both true and false should be in oldspace at all times.
1734 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1735 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1736 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1737 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1738 Smi::FromInt(0),
1739 SKIP_WRITE_BARRIER);
1740 return regexp;
1741 }
1742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001744 PropertyAttributes final =
1745 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1746 PropertyAttributes writable =
1747 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001751 source,
1752 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001755 global,
1756 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 ASSERT(!result->IsFailure());
1758 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001760 ignoreCase,
1761 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001762 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001764 multiline,
1765 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 ASSERT(!result->IsFailure());
1767 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001769 Smi::FromInt(0),
1770 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001771 ASSERT(!result->IsFailure());
1772 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773 return regexp;
1774}
1775
1776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777static MaybeObject* Runtime_FinishArrayPrototypeSetup(
1778 RUNTIME_CALLING_CONVENTION) {
1779 RUNTIME_GET_ISOLATE;
1780 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001781 ASSERT(args.length() == 1);
1782 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1783 // This is necessary to enable fast checks for absence of elements
1784 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001786 return Smi::FromInt(0);
1787}
1788
1789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1791 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001792 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001793 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1795 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1796 Handle<JSFunction> optimized =
1797 isolate->factory()->NewFunction(key,
1798 JS_OBJECT_TYPE,
1799 JSObject::kHeaderSize,
1800 code,
1801 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001802 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001803 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 return optimized;
1805}
1806
1807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808static MaybeObject* Runtime_SpecialArrayFunctions(RUNTIME_CALLING_CONVENTION) {
1809 RUNTIME_GET_ISOLATE;
1810 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001811 ASSERT(args.length() == 1);
1812 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 InstallBuiltin(isolate, holder, "pop", Builtins::ArrayPop);
1815 InstallBuiltin(isolate, holder, "push", Builtins::ArrayPush);
1816 InstallBuiltin(isolate, holder, "shift", Builtins::ArrayShift);
1817 InstallBuiltin(isolate, holder, "unshift", Builtins::ArrayUnshift);
1818 InstallBuiltin(isolate, holder, "slice", Builtins::ArraySlice);
1819 InstallBuiltin(isolate, holder, "splice", Builtins::ArraySplice);
1820 InstallBuiltin(isolate, holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001821
1822 return *holder;
1823}
1824
1825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826static MaybeObject* Runtime_GetGlobalReceiver(RUNTIME_CALLING_CONVENTION) {
1827 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +00001828 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 Context* global_context =
1830 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001831 return global_context->global()->global_receiver();
1832}
1833
1834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001835static MaybeObject* Runtime_MaterializeRegExpLiteral(
1836 RUNTIME_CALLING_CONVENTION) {
1837 RUNTIME_GET_ISOLATE;
1838 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 ASSERT(args.length() == 4);
1840 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1841 int index = Smi::cast(args[1])->value();
1842 Handle<String> pattern = args.at<String>(2);
1843 Handle<String> flags = args.at<String>(3);
1844
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001845 // Get the RegExp function from the context in the literals array.
1846 // This is the RegExp function from the context in which the
1847 // function was created. We do not use the RegExp function from the
1848 // current global context because this might be the RegExp function
1849 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001850 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001851 Handle<JSFunction>(
1852 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853 // Compute the regular expression literal.
1854 bool has_pending_exception;
1855 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001856 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1857 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 return Failure::Exception();
1861 }
1862 literals->set(index, *regexp);
1863 return *regexp;
1864}
1865
1866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867static MaybeObject* Runtime_FunctionGetName(RUNTIME_CALLING_CONVENTION) {
1868 RUNTIME_GET_ISOLATE;
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()->name();
1874}
1875
1876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877static MaybeObject* Runtime_FunctionSetName(RUNTIME_CALLING_CONVENTION) {
1878 RUNTIME_GET_ISOLATE;
ager@chromium.org236ad962008-09-25 09:45:57 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 2);
1881
1882 CONVERT_CHECKED(JSFunction, f, args[0]);
1883 CONVERT_CHECKED(String, name, args[1]);
1884 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001885 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001886}
1887
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889static MaybeObject* Runtime_FunctionRemovePrototype(
1890 RUNTIME_CALLING_CONVENTION) {
1891 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001892 NoHandleAllocation ha;
1893 ASSERT(args.length() == 1);
1894
1895 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 Object* obj = f->RemovePrototype();
1897 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001900}
1901
1902
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001903static MaybeObject* Runtime_FunctionGetScript(RUNTIME_CALLING_CONVENTION) {
1904 RUNTIME_GET_ISOLATE;
1905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1910 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911
1912 return *GetScriptWrapper(Handle<Script>::cast(script));
1913}
1914
1915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916static MaybeObject* Runtime_FunctionGetSourceCode(RUNTIME_CALLING_CONVENTION) {
1917 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 NoHandleAllocation ha;
1919 ASSERT(args.length() == 1);
1920
1921 CONVERT_CHECKED(JSFunction, f, args[0]);
1922 return f->shared()->GetSourceCode();
1923}
1924
1925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926static MaybeObject* Runtime_FunctionGetScriptSourcePosition(
1927 RUNTIME_CALLING_CONVENTION) {
1928 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, fun, args[0]);
1933 int pos = fun->shared()->start_position();
1934 return Smi::FromInt(pos);
1935}
1936
1937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001938static MaybeObject* Runtime_FunctionGetPositionForOffset(
1939 RUNTIME_CALLING_CONVENTION) {
1940 RUNTIME_GET_ISOLATE;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001941 ASSERT(args.length() == 2);
1942
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001943 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001944 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1945
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001946 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1947
1948 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001949 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001950}
1951
1952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001953static MaybeObject* Runtime_FunctionSetInstanceClassName(
1954 RUNTIME_CALLING_CONVENTION) {
1955 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 NoHandleAllocation ha;
1957 ASSERT(args.length() == 2);
1958
1959 CONVERT_CHECKED(JSFunction, fun, args[0]);
1960 CONVERT_CHECKED(String, name, args[1]);
1961 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001962 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963}
1964
1965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966static MaybeObject* Runtime_FunctionSetLength(RUNTIME_CALLING_CONVENTION) {
1967 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001968 NoHandleAllocation ha;
1969 ASSERT(args.length() == 2);
1970
1971 CONVERT_CHECKED(JSFunction, fun, args[0]);
1972 CONVERT_CHECKED(Smi, length, args[1]);
1973 fun->shared()->set_length(length->value());
1974 return length;
1975}
1976
1977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978static MaybeObject* Runtime_FunctionSetPrototype(RUNTIME_CALLING_CONVENTION) {
1979 RUNTIME_GET_ISOLATE;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001980 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 ASSERT(args.length() == 2);
1982
1983 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001984 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001985 Object* obj;
1986 { MaybeObject* maybe_obj =
1987 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1988 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 return args[0]; // return TOS
1991}
1992
1993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994static MaybeObject* Runtime_FunctionIsAPIFunction(RUNTIME_CALLING_CONVENTION) {
1995 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
1999 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
2001 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002002}
2003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004
2005static MaybeObject* Runtime_FunctionIsBuiltin(RUNTIME_CALLING_CONVENTION) {
2006 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002007 NoHandleAllocation ha;
2008 ASSERT(args.length() == 1);
2009
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002011 return f->IsBuiltin() ? isolate->heap()->true_value() :
2012 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002013}
2014
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002016static MaybeObject* Runtime_SetCode(RUNTIME_CALLING_CONVENTION) {
2017 RUNTIME_GET_ISOLATE;
2018 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 ASSERT(args.length() == 2);
2020
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002021 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 Handle<Object> code = args.at<Object>(1);
2023
2024 Handle<Context> context(target->context());
2025
2026 if (!code->IsNull()) {
2027 RUNTIME_ASSERT(code->IsJSFunction());
2028 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002029 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002030
2031 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002032 return Failure::Exception();
2033 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002034 // Since we don't store the source for this we should never
2035 // optimize this.
2036 shared->code()->set_optimizable(false);
2037
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002038 // Set the code, scope info, formal parameter count,
2039 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002040 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002042 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002043 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002045 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002046 // Set the source code of the target function to undefined.
2047 // SetCode is only used for built-in constructors like String,
2048 // Array, and Object, and some web code
2049 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002051 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002052 // Clear the optimization hints related to the compiled code as these are no
2053 // longer valid when the code is overwritten.
2054 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 context = Handle<Context>(fun->context());
2056
2057 // Make sure we get a fresh copy of the literal vector to avoid
2058 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002059 int number_of_literals = fun->NumberOfLiterals();
2060 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002063 // Insert the object, regexp and array functions in the literals
2064 // array prefix. These are the functions that will be used when
2065 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002066 literals->set(JSFunction::kLiteralGlobalContextIndex,
2067 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002069 // It's okay to skip the write barrier here because the literals
2070 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002071 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 }
2074
2075 target->set_context(*context);
2076 return *target;
2077}
2078
2079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080static MaybeObject* Runtime_SetExpectedNumberOfProperties(
2081 RUNTIME_CALLING_CONVENTION) {
2082 RUNTIME_GET_ISOLATE;
2083 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002084 ASSERT(args.length() == 2);
2085 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2086 CONVERT_SMI_CHECKED(num, args[1]);
2087 RUNTIME_ASSERT(num >= 0);
2088 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002090}
2091
2092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002093MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2094 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002095 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002096 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002097 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002098 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002099 }
2100 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002101 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002102}
2103
2104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002105static MaybeObject* Runtime_StringCharCodeAt(RUNTIME_CALLING_CONVENTION) {
2106 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 NoHandleAllocation ha;
2108 ASSERT(args.length() == 2);
2109
2110 CONVERT_CHECKED(String, subject, args[0]);
2111 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002112 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002113
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002114 uint32_t i = 0;
2115 if (index->IsSmi()) {
2116 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002117 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002118 i = value;
2119 } else {
2120 ASSERT(index->IsHeapNumber());
2121 double value = HeapNumber::cast(index)->value();
2122 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002123 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002124
2125 // Flatten the string. If someone wants to get a char at an index
2126 // in a cons string, it is likely that more indices will be
2127 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002128 Object* flat;
2129 { MaybeObject* maybe_flat = subject->TryFlatten();
2130 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2131 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002132 subject = String::cast(flat);
2133
2134 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002135 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002136 }
2137
2138 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002139}
2140
2141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142static MaybeObject* Runtime_CharFromCode(RUNTIME_CALLING_CONVENTION) {
2143 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 NoHandleAllocation ha;
2145 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147}
2148
lrn@chromium.org25156de2010-04-06 13:10:27 +00002149
2150class FixedArrayBuilder {
2151 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2153 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002154 length_(0) {
2155 // Require a non-zero initial size. Ensures that doubling the size to
2156 // extend the array will work.
2157 ASSERT(initial_capacity > 0);
2158 }
2159
2160 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2161 : array_(backing_store),
2162 length_(0) {
2163 // Require a non-zero initial size. Ensures that doubling the size to
2164 // extend the array will work.
2165 ASSERT(backing_store->length() > 0);
2166 }
2167
2168 bool HasCapacity(int elements) {
2169 int length = array_->length();
2170 int required_length = length_ + elements;
2171 return (length >= required_length);
2172 }
2173
2174 void EnsureCapacity(int elements) {
2175 int length = array_->length();
2176 int required_length = length_ + elements;
2177 if (length < required_length) {
2178 int new_length = length;
2179 do {
2180 new_length *= 2;
2181 } while (new_length < required_length);
2182 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002184 array_->CopyTo(0, *extended_array, 0, length_);
2185 array_ = extended_array;
2186 }
2187 }
2188
2189 void Add(Object* value) {
2190 ASSERT(length_ < capacity());
2191 array_->set(length_, value);
2192 length_++;
2193 }
2194
2195 void Add(Smi* value) {
2196 ASSERT(length_ < capacity());
2197 array_->set(length_, value);
2198 length_++;
2199 }
2200
2201 Handle<FixedArray> array() {
2202 return array_;
2203 }
2204
2205 int length() {
2206 return length_;
2207 }
2208
2209 int capacity() {
2210 return array_->length();
2211 }
2212
2213 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002215 result_array->set_length(Smi::FromInt(length_));
2216 return result_array;
2217 }
2218
2219 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2220 target_array->set_elements(*array_);
2221 target_array->set_length(Smi::FromInt(length_));
2222 return target_array;
2223 }
2224
2225 private:
2226 Handle<FixedArray> array_;
2227 int length_;
2228};
2229
2230
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002231// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002232const int kStringBuilderConcatHelperLengthBits = 11;
2233const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002234
2235template <typename schar>
2236static inline void StringBuilderConcatHelper(String*,
2237 schar*,
2238 FixedArray*,
2239 int);
2240
lrn@chromium.org25156de2010-04-06 13:10:27 +00002241typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2242 StringBuilderSubstringLength;
2243typedef BitField<int,
2244 kStringBuilderConcatHelperLengthBits,
2245 kStringBuilderConcatHelperPositionBits>
2246 StringBuilderSubstringPosition;
2247
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002248
2249class ReplacementStringBuilder {
2250 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002251 ReplacementStringBuilder(Heap* heap,
2252 Handle<String> subject,
2253 int estimated_part_count)
2254 : heap_(heap),
2255 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002258 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002259 // Require a non-zero initial size. Ensures that doubling the size to
2260 // extend the array will work.
2261 ASSERT(estimated_part_count > 0);
2262 }
2263
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2265 int from,
2266 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 ASSERT(from >= 0);
2268 int length = to - from;
2269 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 if (StringBuilderSubstringLength::is_valid(length) &&
2271 StringBuilderSubstringPosition::is_valid(from)) {
2272 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2273 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002274 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002275 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002276 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002277 builder->Add(Smi::FromInt(-length));
2278 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002279 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
2281
2282
2283 void EnsureCapacity(int elements) {
2284 array_builder_.EnsureCapacity(elements);
2285 }
2286
2287
2288 void AddSubjectSlice(int from, int to) {
2289 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002291 }
2292
2293
2294 void AddString(Handle<String> string) {
2295 int length = string->length();
2296 ASSERT(length > 0);
2297 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002298 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 is_ascii_ = false;
2300 }
2301 IncrementCharacterCount(length);
2302 }
2303
2304
2305 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002307 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308 }
2309
2310 Handle<String> joined_string;
2311 if (is_ascii_) {
2312 joined_string = NewRawAsciiString(character_count_);
2313 AssertNoAllocation no_alloc;
2314 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2315 char* char_buffer = seq->GetChars();
2316 StringBuilderConcatHelper(*subject_,
2317 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002318 *array_builder_.array(),
2319 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002320 } else {
2321 // Non-ASCII.
2322 joined_string = NewRawTwoByteString(character_count_);
2323 AssertNoAllocation no_alloc;
2324 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2325 uc16* char_buffer = seq->GetChars();
2326 StringBuilderConcatHelper(*subject_,
2327 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 *array_builder_.array(),
2329 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 }
2331 return joined_string;
2332 }
2333
2334
2335 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002336 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002337 V8::FatalProcessOutOfMemory("String.replace result too large.");
2338 }
2339 character_count_ += by;
2340 }
2341
lrn@chromium.org25156de2010-04-06 13:10:27 +00002342 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002345
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002347 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 CALL_HEAP_FUNCTION(heap_->isolate(),
2349 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002350 }
2351
2352
2353 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002354 CALL_HEAP_FUNCTION(heap_->isolate(),
2355 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002356 }
2357
2358
2359 void AddElement(Object* element) {
2360 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002361 ASSERT(array_builder_.capacity() > array_builder_.length());
2362 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 }
2364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368 int character_count_;
2369 bool is_ascii_;
2370};
2371
2372
2373class CompiledReplacement {
2374 public:
2375 CompiledReplacement()
2376 : parts_(1), replacement_substrings_(0) {}
2377
2378 void Compile(Handle<String> replacement,
2379 int capture_count,
2380 int subject_length);
2381
2382 void Apply(ReplacementStringBuilder* builder,
2383 int match_from,
2384 int match_to,
2385 Handle<JSArray> last_match_info);
2386
2387 // Number of distinct parts of the replacement pattern.
2388 int parts() {
2389 return parts_.length();
2390 }
2391 private:
2392 enum PartType {
2393 SUBJECT_PREFIX = 1,
2394 SUBJECT_SUFFIX,
2395 SUBJECT_CAPTURE,
2396 REPLACEMENT_SUBSTRING,
2397 REPLACEMENT_STRING,
2398
2399 NUMBER_OF_PART_TYPES
2400 };
2401
2402 struct ReplacementPart {
2403 static inline ReplacementPart SubjectMatch() {
2404 return ReplacementPart(SUBJECT_CAPTURE, 0);
2405 }
2406 static inline ReplacementPart SubjectCapture(int capture_index) {
2407 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2408 }
2409 static inline ReplacementPart SubjectPrefix() {
2410 return ReplacementPart(SUBJECT_PREFIX, 0);
2411 }
2412 static inline ReplacementPart SubjectSuffix(int subject_length) {
2413 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2414 }
2415 static inline ReplacementPart ReplacementString() {
2416 return ReplacementPart(REPLACEMENT_STRING, 0);
2417 }
2418 static inline ReplacementPart ReplacementSubString(int from, int to) {
2419 ASSERT(from >= 0);
2420 ASSERT(to > from);
2421 return ReplacementPart(-from, to);
2422 }
2423
2424 // If tag <= 0 then it is the negation of a start index of a substring of
2425 // the replacement pattern, otherwise it's a value from PartType.
2426 ReplacementPart(int tag, int data)
2427 : tag(tag), data(data) {
2428 // Must be non-positive or a PartType value.
2429 ASSERT(tag < NUMBER_OF_PART_TYPES);
2430 }
2431 // Either a value of PartType or a non-positive number that is
2432 // the negation of an index into the replacement string.
2433 int tag;
2434 // The data value's interpretation depends on the value of tag:
2435 // tag == SUBJECT_PREFIX ||
2436 // tag == SUBJECT_SUFFIX: data is unused.
2437 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2438 // tag == REPLACEMENT_SUBSTRING ||
2439 // tag == REPLACEMENT_STRING: data is index into array of substrings
2440 // of the replacement string.
2441 // tag <= 0: Temporary representation of the substring of the replacement
2442 // string ranging over -tag .. data.
2443 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2444 // substring objects.
2445 int data;
2446 };
2447
2448 template<typename Char>
2449 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2450 Vector<Char> characters,
2451 int capture_count,
2452 int subject_length) {
2453 int length = characters.length();
2454 int last = 0;
2455 for (int i = 0; i < length; i++) {
2456 Char c = characters[i];
2457 if (c == '$') {
2458 int next_index = i + 1;
2459 if (next_index == length) { // No next character!
2460 break;
2461 }
2462 Char c2 = characters[next_index];
2463 switch (c2) {
2464 case '$':
2465 if (i > last) {
2466 // There is a substring before. Include the first "$".
2467 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2468 last = next_index + 1; // Continue after the second "$".
2469 } else {
2470 // Let the next substring start with the second "$".
2471 last = next_index;
2472 }
2473 i = next_index;
2474 break;
2475 case '`':
2476 if (i > last) {
2477 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2478 }
2479 parts->Add(ReplacementPart::SubjectPrefix());
2480 i = next_index;
2481 last = i + 1;
2482 break;
2483 case '\'':
2484 if (i > last) {
2485 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2486 }
2487 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2488 i = next_index;
2489 last = i + 1;
2490 break;
2491 case '&':
2492 if (i > last) {
2493 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2494 }
2495 parts->Add(ReplacementPart::SubjectMatch());
2496 i = next_index;
2497 last = i + 1;
2498 break;
2499 case '0':
2500 case '1':
2501 case '2':
2502 case '3':
2503 case '4':
2504 case '5':
2505 case '6':
2506 case '7':
2507 case '8':
2508 case '9': {
2509 int capture_ref = c2 - '0';
2510 if (capture_ref > capture_count) {
2511 i = next_index;
2512 continue;
2513 }
2514 int second_digit_index = next_index + 1;
2515 if (second_digit_index < length) {
2516 // Peek ahead to see if we have two digits.
2517 Char c3 = characters[second_digit_index];
2518 if ('0' <= c3 && c3 <= '9') { // Double digits.
2519 int double_digit_ref = capture_ref * 10 + c3 - '0';
2520 if (double_digit_ref <= capture_count) {
2521 next_index = second_digit_index;
2522 capture_ref = double_digit_ref;
2523 }
2524 }
2525 }
2526 if (capture_ref > 0) {
2527 if (i > last) {
2528 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2529 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002530 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002531 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2532 last = next_index + 1;
2533 }
2534 i = next_index;
2535 break;
2536 }
2537 default:
2538 i = next_index;
2539 break;
2540 }
2541 }
2542 }
2543 if (length > last) {
2544 if (last == 0) {
2545 parts->Add(ReplacementPart::ReplacementString());
2546 } else {
2547 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2548 }
2549 }
2550 }
2551
2552 ZoneList<ReplacementPart> parts_;
2553 ZoneList<Handle<String> > replacement_substrings_;
2554};
2555
2556
2557void CompiledReplacement::Compile(Handle<String> replacement,
2558 int capture_count,
2559 int subject_length) {
2560 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002561 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 AssertNoAllocation no_alloc;
2563 ParseReplacementPattern(&parts_,
2564 replacement->ToAsciiVector(),
2565 capture_count,
2566 subject_length);
2567 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002568 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002569 AssertNoAllocation no_alloc;
2570
2571 ParseReplacementPattern(&parts_,
2572 replacement->ToUC16Vector(),
2573 capture_count,
2574 subject_length);
2575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002576 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002577 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002578 int substring_index = 0;
2579 for (int i = 0, n = parts_.length(); i < n; i++) {
2580 int tag = parts_[i].tag;
2581 if (tag <= 0) { // A replacement string slice.
2582 int from = -tag;
2583 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002584 replacement_substrings_.Add(
2585 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002586 parts_[i].tag = REPLACEMENT_SUBSTRING;
2587 parts_[i].data = substring_index;
2588 substring_index++;
2589 } else if (tag == REPLACEMENT_STRING) {
2590 replacement_substrings_.Add(replacement);
2591 parts_[i].data = substring_index;
2592 substring_index++;
2593 }
2594 }
2595}
2596
2597
2598void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2599 int match_from,
2600 int match_to,
2601 Handle<JSArray> last_match_info) {
2602 for (int i = 0, n = parts_.length(); i < n; i++) {
2603 ReplacementPart part = parts_[i];
2604 switch (part.tag) {
2605 case SUBJECT_PREFIX:
2606 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2607 break;
2608 case SUBJECT_SUFFIX: {
2609 int subject_length = part.data;
2610 if (match_to < subject_length) {
2611 builder->AddSubjectSlice(match_to, subject_length);
2612 }
2613 break;
2614 }
2615 case SUBJECT_CAPTURE: {
2616 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002617 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002618 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2619 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2620 if (from >= 0 && to > from) {
2621 builder->AddSubjectSlice(from, to);
2622 }
2623 break;
2624 }
2625 case REPLACEMENT_SUBSTRING:
2626 case REPLACEMENT_STRING:
2627 builder->AddString(replacement_substrings_[part.data]);
2628 break;
2629 default:
2630 UNREACHABLE();
2631 }
2632 }
2633}
2634
2635
2636
lrn@chromium.org303ada72010-10-27 09:33:13 +00002637MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002638 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002639 String* subject,
2640 JSRegExp* regexp,
2641 String* replacement,
2642 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002643 ASSERT(subject->IsFlat());
2644 ASSERT(replacement->IsFlat());
2645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002646 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002647
2648 int length = subject->length();
2649 Handle<String> subject_handle(subject);
2650 Handle<JSRegExp> regexp_handle(regexp);
2651 Handle<String> replacement_handle(replacement);
2652 Handle<JSArray> last_match_info_handle(last_match_info);
2653 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2654 subject_handle,
2655 0,
2656 last_match_info_handle);
2657 if (match.is_null()) {
2658 return Failure::Exception();
2659 }
2660 if (match->IsNull()) {
2661 return *subject_handle;
2662 }
2663
2664 int capture_count = regexp_handle->CaptureCount();
2665
2666 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002667 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 CompiledReplacement compiled_replacement;
2669 compiled_replacement.Compile(replacement_handle,
2670 capture_count,
2671 length);
2672
2673 bool is_global = regexp_handle->GetFlags().is_global();
2674
2675 // Guessing the number of parts that the final result string is built
2676 // from. Global regexps can match any number of times, so we guess
2677 // conservatively.
2678 int expected_parts =
2679 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002680 ReplacementStringBuilder builder(isolate->heap(),
2681 subject_handle,
2682 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683
2684 // Index of end of last match.
2685 int prev = 0;
2686
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002687 // Number of parts added by compiled replacement plus preceeding
2688 // string and possibly suffix after last match. It is possible for
2689 // all components to use two elements when encoded as two smis.
2690 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 bool matched = true;
2692 do {
2693 ASSERT(last_match_info_handle->HasFastElements());
2694 // Increase the capacity of the builder before entering local handle-scope,
2695 // so its internal buffer can safely allocate a new handle if it grows.
2696 builder.EnsureCapacity(parts_added_per_loop);
2697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 int start, end;
2700 {
2701 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002702 FixedArray* match_info_array =
2703 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704
2705 ASSERT_EQ(capture_count * 2 + 2,
2706 RegExpImpl::GetLastCaptureCount(match_info_array));
2707 start = RegExpImpl::GetCapture(match_info_array, 0);
2708 end = RegExpImpl::GetCapture(match_info_array, 1);
2709 }
2710
2711 if (prev < start) {
2712 builder.AddSubjectSlice(prev, start);
2713 }
2714 compiled_replacement.Apply(&builder,
2715 start,
2716 end,
2717 last_match_info_handle);
2718 prev = end;
2719
2720 // Only continue checking for global regexps.
2721 if (!is_global) break;
2722
2723 // Continue from where the match ended, unless it was an empty match.
2724 int next = end;
2725 if (start == end) {
2726 next = end + 1;
2727 if (next > length) break;
2728 }
2729
2730 match = RegExpImpl::Exec(regexp_handle,
2731 subject_handle,
2732 next,
2733 last_match_info_handle);
2734 if (match.is_null()) {
2735 return Failure::Exception();
2736 }
2737 matched = !match->IsNull();
2738 } while (matched);
2739
2740 if (prev < length) {
2741 builder.AddSubjectSlice(prev, length);
2742 }
2743
2744 return *(builder.ToString());
2745}
2746
2747
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002748template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002749MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002750 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751 String* subject,
2752 JSRegExp* regexp,
2753 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002754 ASSERT(subject->IsFlat());
2755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002756 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002757
2758 Handle<String> subject_handle(subject);
2759 Handle<JSRegExp> regexp_handle(regexp);
2760 Handle<JSArray> last_match_info_handle(last_match_info);
2761 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2762 subject_handle,
2763 0,
2764 last_match_info_handle);
2765 if (match.is_null()) return Failure::Exception();
2766 if (match->IsNull()) return *subject_handle;
2767
2768 ASSERT(last_match_info_handle->HasFastElements());
2769
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002770 int start, end;
2771 {
2772 AssertNoAllocation match_info_array_is_not_in_a_handle;
2773 FixedArray* match_info_array =
2774 FixedArray::cast(last_match_info_handle->elements());
2775
2776 start = RegExpImpl::GetCapture(match_info_array, 0);
2777 end = RegExpImpl::GetCapture(match_info_array, 1);
2778 }
2779
2780 int length = subject->length();
2781 int new_length = length - (end - start);
2782 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002783 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002784 }
2785 Handle<ResultSeqString> answer;
2786 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 answer = Handle<ResultSeqString>::cast(
2788 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002789 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002790 answer = Handle<ResultSeqString>::cast(
2791 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002792 }
2793
2794 // If the regexp isn't global, only match once.
2795 if (!regexp_handle->GetFlags().is_global()) {
2796 if (start > 0) {
2797 String::WriteToFlat(*subject_handle,
2798 answer->GetChars(),
2799 0,
2800 start);
2801 }
2802 if (end < length) {
2803 String::WriteToFlat(*subject_handle,
2804 answer->GetChars() + start,
2805 end,
2806 length);
2807 }
2808 return *answer;
2809 }
2810
2811 int prev = 0; // Index of end of last match.
2812 int next = 0; // Start of next search (prev unless last match was empty).
2813 int position = 0;
2814
2815 do {
2816 if (prev < start) {
2817 // Add substring subject[prev;start] to answer string.
2818 String::WriteToFlat(*subject_handle,
2819 answer->GetChars() + position,
2820 prev,
2821 start);
2822 position += start - prev;
2823 }
2824 prev = end;
2825 next = end;
2826 // Continue from where the match ended, unless it was an empty match.
2827 if (start == end) {
2828 next++;
2829 if (next > length) break;
2830 }
2831 match = RegExpImpl::Exec(regexp_handle,
2832 subject_handle,
2833 next,
2834 last_match_info_handle);
2835 if (match.is_null()) return Failure::Exception();
2836 if (match->IsNull()) break;
2837
2838 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002839 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002840 {
2841 AssertNoAllocation match_info_array_is_not_in_a_handle;
2842 FixedArray* match_info_array =
2843 FixedArray::cast(last_match_info_handle->elements());
2844 start = RegExpImpl::GetCapture(match_info_array, 0);
2845 end = RegExpImpl::GetCapture(match_info_array, 1);
2846 }
2847 } while (true);
2848
2849 if (prev < length) {
2850 // Add substring subject[prev;length] to answer string.
2851 String::WriteToFlat(*subject_handle,
2852 answer->GetChars() + position,
2853 prev,
2854 length);
2855 position += length - prev;
2856 }
2857
2858 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002859 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002860 }
2861
2862 // Shorten string and fill
2863 int string_size = ResultSeqString::SizeFor(position);
2864 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2865 int delta = allocated_string_size - string_size;
2866
2867 answer->set_length(position);
2868 if (delta == 0) return *answer;
2869
2870 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002871 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002872
2873 return *answer;
2874}
2875
2876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877static MaybeObject* Runtime_StringReplaceRegExpWithString(
2878 RUNTIME_CALLING_CONVENTION) {
2879 RUNTIME_GET_ISOLATE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002880 ASSERT(args.length() == 4);
2881
2882 CONVERT_CHECKED(String, subject, args[0]);
2883 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002884 Object* flat_subject;
2885 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2886 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2887 return maybe_flat_subject;
2888 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002889 }
2890 subject = String::cast(flat_subject);
2891 }
2892
2893 CONVERT_CHECKED(String, replacement, args[2]);
2894 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002895 Object* flat_replacement;
2896 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2897 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2898 return maybe_flat_replacement;
2899 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002900 }
2901 replacement = String::cast(flat_replacement);
2902 }
2903
2904 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2905 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2906
2907 ASSERT(last_match_info->HasFastElements());
2908
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002909 if (replacement->length() == 0) {
2910 if (subject->HasOnlyAsciiChars()) {
2911 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002912 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002913 } else {
2914 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002916 }
2917 }
2918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 return StringReplaceRegExpWithString(isolate,
2920 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002921 regexp,
2922 replacement,
2923 last_match_info);
2924}
2925
2926
ager@chromium.org7c537e22008-10-16 08:43:32 +00002927// Perform string match of pattern on subject, starting at start index.
2928// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002929// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002930int Runtime::StringMatch(Isolate* isolate,
2931 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002932 Handle<String> pat,
2933 int start_index) {
2934 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002935 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002936
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002937 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002938 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002939
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002940 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002941 if (start_index + pattern_length > subject_length) return -1;
2942
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002943 if (!sub->IsFlat()) FlattenString(sub);
2944 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002945
ager@chromium.org7c537e22008-10-16 08:43:32 +00002946 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002947 // Extract flattened substrings of cons strings before determining asciiness.
2948 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002949 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002950 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002951 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002952
ager@chromium.org7c537e22008-10-16 08:43:32 +00002953 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002954 if (seq_pat->IsAsciiRepresentation()) {
2955 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2956 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 return SearchString(isolate,
2958 seq_sub->ToAsciiVector(),
2959 pat_vector,
2960 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002962 return SearchString(isolate,
2963 seq_sub->ToUC16Vector(),
2964 pat_vector,
2965 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002966 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002967 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2968 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 return SearchString(isolate,
2970 seq_sub->ToAsciiVector(),
2971 pat_vector,
2972 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 return SearchString(isolate,
2975 seq_sub->ToUC16Vector(),
2976 pat_vector,
2977 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002978}
2979
2980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002981static MaybeObject* Runtime_StringIndexOf(RUNTIME_CALLING_CONVENTION) {
2982 RUNTIME_GET_ISOLATE;
2983 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002984 ASSERT(args.length() == 3);
2985
ager@chromium.org7c537e22008-10-16 08:43:32 +00002986 CONVERT_ARG_CHECKED(String, sub, 0);
2987 CONVERT_ARG_CHECKED(String, pat, 1);
2988
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002989 Object* index = args[2];
2990 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002991 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002992
ager@chromium.org870a0b62008-11-04 11:43:05 +00002993 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 int position =
2995 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002996 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002997}
2998
2999
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003000template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003001static int StringMatchBackwards(Vector<const schar> subject,
3002 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003004 int pattern_length = pattern.length();
3005 ASSERT(pattern_length >= 1);
3006 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003007
3008 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003009 for (int i = 0; i < pattern_length; i++) {
3010 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 if (c > String::kMaxAsciiCharCode) {
3012 return -1;
3013 }
3014 }
3015 }
3016
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003017 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003018 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003019 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003020 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003021 while (j < pattern_length) {
3022 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003023 break;
3024 }
3025 j++;
3026 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003027 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003028 return i;
3029 }
3030 }
3031 return -1;
3032}
3033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034static MaybeObject* Runtime_StringLastIndexOf(RUNTIME_CALLING_CONVENTION) {
3035 RUNTIME_GET_ISOLATE;
3036 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003037 ASSERT(args.length() == 3);
3038
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003039 CONVERT_ARG_CHECKED(String, sub, 0);
3040 CONVERT_ARG_CHECKED(String, pat, 1);
3041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003042 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003044 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003045
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003046 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003047 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003048
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003049 if (start_index + pat_length > sub_length) {
3050 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003051 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003052
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003053 if (pat_length == 0) {
3054 return Smi::FromInt(start_index);
3055 }
3056
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003057 if (!sub->IsFlat()) FlattenString(sub);
3058 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003059
3060 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3061
3062 int position = -1;
3063
3064 if (pat->IsAsciiRepresentation()) {
3065 Vector<const char> pat_vector = pat->ToAsciiVector();
3066 if (sub->IsAsciiRepresentation()) {
3067 position = StringMatchBackwards(sub->ToAsciiVector(),
3068 pat_vector,
3069 start_index);
3070 } else {
3071 position = StringMatchBackwards(sub->ToUC16Vector(),
3072 pat_vector,
3073 start_index);
3074 }
3075 } else {
3076 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3077 if (sub->IsAsciiRepresentation()) {
3078 position = StringMatchBackwards(sub->ToAsciiVector(),
3079 pat_vector,
3080 start_index);
3081 } else {
3082 position = StringMatchBackwards(sub->ToUC16Vector(),
3083 pat_vector,
3084 start_index);
3085 }
3086 }
3087
3088 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003089}
3090
3091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003092static MaybeObject* Runtime_StringLocaleCompare(RUNTIME_CALLING_CONVENTION) {
3093 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003094 NoHandleAllocation ha;
3095 ASSERT(args.length() == 2);
3096
3097 CONVERT_CHECKED(String, str1, args[0]);
3098 CONVERT_CHECKED(String, str2, args[1]);
3099
3100 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003101 int str1_length = str1->length();
3102 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103
3104 // Decide trivial cases without flattening.
3105 if (str1_length == 0) {
3106 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3107 return Smi::FromInt(-str2_length);
3108 } else {
3109 if (str2_length == 0) return Smi::FromInt(str1_length);
3110 }
3111
3112 int end = str1_length < str2_length ? str1_length : str2_length;
3113
3114 // No need to flatten if we are going to find the answer on the first
3115 // character. At this point we know there is at least one character
3116 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003117 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 if (d != 0) return Smi::FromInt(d);
3119
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003120 str1->TryFlatten();
3121 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003123 StringInputBuffer& buf1 =
3124 *isolate->runtime_state()->string_locale_compare_buf1();
3125 StringInputBuffer& buf2 =
3126 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127
3128 buf1.Reset(str1);
3129 buf2.Reset(str2);
3130
3131 for (int i = 0; i < end; i++) {
3132 uint16_t char1 = buf1.GetNext();
3133 uint16_t char2 = buf2.GetNext();
3134 if (char1 != char2) return Smi::FromInt(char1 - char2);
3135 }
3136
3137 return Smi::FromInt(str1_length - str2_length);
3138}
3139
3140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003141static MaybeObject* Runtime_SubString(RUNTIME_CALLING_CONVENTION) {
3142 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 NoHandleAllocation ha;
3144 ASSERT(args.length() == 3);
3145
3146 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003147 Object* from = args[1];
3148 Object* to = args[2];
3149 int start, end;
3150 // We have a fast integer-only case here to avoid a conversion to double in
3151 // the common case where from and to are Smis.
3152 if (from->IsSmi() && to->IsSmi()) {
3153 start = Smi::cast(from)->value();
3154 end = Smi::cast(to)->value();
3155 } else {
3156 CONVERT_DOUBLE_CHECKED(from_number, from);
3157 CONVERT_DOUBLE_CHECKED(to_number, to);
3158 start = FastD2I(from_number);
3159 end = FastD2I(to_number);
3160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003161 RUNTIME_ASSERT(end >= start);
3162 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003163 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003164 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003165 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003166}
3167
3168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003169static MaybeObject* Runtime_StringMatch(RUNTIME_CALLING_CONVENTION) {
3170 RUNTIME_GET_ISOLATE;
ager@chromium.org41826e72009-03-30 13:30:57 +00003171 ASSERT_EQ(3, args.length());
3172
3173 CONVERT_ARG_CHECKED(String, subject, 0);
3174 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3175 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3176 HandleScope handles;
3177
3178 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3179
3180 if (match.is_null()) {
3181 return Failure::Exception();
3182 }
3183 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003185 }
3186 int length = subject->length();
3187
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003188 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003189 ZoneList<int> offsets(8);
3190 do {
3191 int start;
3192 int end;
3193 {
3194 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003195 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003196 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3197 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3198 }
3199 offsets.Add(start);
3200 offsets.Add(end);
3201 int index = start < end ? end : end + 1;
3202 if (index > length) break;
3203 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3204 if (match.is_null()) {
3205 return Failure::Exception();
3206 }
3207 } while (!match->IsNull());
3208 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003209 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003210 for (int i = 0; i < matches ; i++) {
3211 int from = offsets.at(i * 2);
3212 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003213 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003214 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003217 result->set_length(Smi::FromInt(matches));
3218 return *result;
3219}
3220
3221
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222// Two smis before and after the match, for very long strings.
3223const int kMaxBuilderEntriesPerRegExpMatch = 5;
3224
3225
3226static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3227 Handle<JSArray> last_match_info,
3228 int match_start,
3229 int match_end) {
3230 // Fill last_match_info with a single capture.
3231 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3232 AssertNoAllocation no_gc;
3233 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3234 RegExpImpl::SetLastCaptureCount(elements, 2);
3235 RegExpImpl::SetLastInput(elements, *subject);
3236 RegExpImpl::SetLastSubject(elements, *subject);
3237 RegExpImpl::SetCapture(elements, 0, match_start);
3238 RegExpImpl::SetCapture(elements, 1, match_end);
3239}
3240
3241
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003243static bool SearchStringMultiple(Isolate* isolate,
3244 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003245 Vector<const PatternChar> pattern,
3246 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003247 FixedArrayBuilder* builder,
3248 int* match_pos) {
3249 int pos = *match_pos;
3250 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003251 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003254 while (pos <= max_search_start) {
3255 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3256 *match_pos = pos;
3257 return false;
3258 }
3259 // Position of end of previous match.
3260 int match_end = pos + pattern_length;
3261 int new_pos = search.Search(subject, match_end);
3262 if (new_pos >= 0) {
3263 // A match.
3264 if (new_pos > match_end) {
3265 ReplacementStringBuilder::AddSubjectSlice(builder,
3266 match_end,
3267 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003268 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003269 pos = new_pos;
3270 builder->Add(pattern_string);
3271 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003275
lrn@chromium.org25156de2010-04-06 13:10:27 +00003276 if (pos < max_search_start) {
3277 ReplacementStringBuilder::AddSubjectSlice(builder,
3278 pos + pattern_length,
3279 subject_length);
3280 }
3281 *match_pos = pos;
3282 return true;
3283}
3284
3285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286static bool SearchStringMultiple(Isolate* isolate,
3287 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003288 Handle<String> pattern,
3289 Handle<JSArray> last_match_info,
3290 FixedArrayBuilder* builder) {
3291 ASSERT(subject->IsFlat());
3292 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293
3294 // Treating as if a previous match was before first character.
3295 int match_pos = -pattern->length();
3296
3297 for (;;) { // Break when search complete.
3298 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3299 AssertNoAllocation no_gc;
3300 if (subject->IsAsciiRepresentation()) {
3301 Vector<const char> subject_vector = subject->ToAsciiVector();
3302 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003303 if (SearchStringMultiple(isolate,
3304 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003305 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003306 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 builder,
3308 &match_pos)) break;
3309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 if (SearchStringMultiple(isolate,
3311 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003312 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003313 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003314 builder,
3315 &match_pos)) break;
3316 }
3317 } else {
3318 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3319 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 if (SearchStringMultiple(isolate,
3321 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003323 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003324 builder,
3325 &match_pos)) break;
3326 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003327 if (SearchStringMultiple(isolate,
3328 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003329 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003330 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003331 builder,
3332 &match_pos)) break;
3333 }
3334 }
3335 }
3336
3337 if (match_pos >= 0) {
3338 SetLastMatchInfoNoCaptures(subject,
3339 last_match_info,
3340 match_pos,
3341 match_pos + pattern->length());
3342 return true;
3343 }
3344 return false; // No matches at all.
3345}
3346
3347
3348static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003350 Handle<String> subject,
3351 Handle<JSRegExp> regexp,
3352 Handle<JSArray> last_match_array,
3353 FixedArrayBuilder* builder) {
3354 ASSERT(subject->IsFlat());
3355 int match_start = -1;
3356 int match_end = 0;
3357 int pos = 0;
3358 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3359 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3360
3361 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003362 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003363 int subject_length = subject->length();
3364
3365 for (;;) { // Break on failure, return on exception.
3366 RegExpImpl::IrregexpResult result =
3367 RegExpImpl::IrregexpExecOnce(regexp,
3368 subject,
3369 pos,
3370 register_vector);
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 match_start = register_vector[0];
3373 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3374 if (match_end < match_start) {
3375 ReplacementStringBuilder::AddSubjectSlice(builder,
3376 match_end,
3377 match_start);
3378 }
3379 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 HandleScope loop_scope(isolate);
3381 builder->Add(*isolate->factory()->NewSubString(subject,
3382 match_start,
3383 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 if (match_start != match_end) {
3385 pos = match_end;
3386 } else {
3387 pos = match_end + 1;
3388 if (pos > subject_length) break;
3389 }
3390 } else if (result == RegExpImpl::RE_FAILURE) {
3391 break;
3392 } else {
3393 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3394 return result;
3395 }
3396 }
3397
3398 if (match_start >= 0) {
3399 if (match_end < subject_length) {
3400 ReplacementStringBuilder::AddSubjectSlice(builder,
3401 match_end,
3402 subject_length);
3403 }
3404 SetLastMatchInfoNoCaptures(subject,
3405 last_match_array,
3406 match_start,
3407 match_end);
3408 return RegExpImpl::RE_SUCCESS;
3409 } else {
3410 return RegExpImpl::RE_FAILURE; // No matches at all.
3411 }
3412}
3413
3414
3415static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003416 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003417 Handle<String> subject,
3418 Handle<JSRegExp> regexp,
3419 Handle<JSArray> last_match_array,
3420 FixedArrayBuilder* builder) {
3421
3422 ASSERT(subject->IsFlat());
3423 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3424 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3425
3426 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003427 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003428
3429 RegExpImpl::IrregexpResult result =
3430 RegExpImpl::IrregexpExecOnce(regexp,
3431 subject,
3432 0,
3433 register_vector);
3434
3435 int capture_count = regexp->CaptureCount();
3436 int subject_length = subject->length();
3437
3438 // Position to search from.
3439 int pos = 0;
3440 // End of previous match. Differs from pos if match was empty.
3441 int match_end = 0;
3442 if (result == RegExpImpl::RE_SUCCESS) {
3443 // Need to keep a copy of the previous match for creating last_match_info
3444 // at the end, so we have two vectors that we swap between.
3445 OffsetsVector registers2(required_registers);
3446 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3447
3448 do {
3449 int match_start = register_vector[0];
3450 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3451 if (match_end < match_start) {
3452 ReplacementStringBuilder::AddSubjectSlice(builder,
3453 match_end,
3454 match_start);
3455 }
3456 match_end = register_vector[1];
3457
3458 {
3459 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003460 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003461 // Arguments array to replace function is match, captures, index and
3462 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003463 Handle<FixedArray> elements =
3464 isolate->factory()->NewFixedArray(3 + capture_count);
3465 Handle<String> match = isolate->factory()->NewSubString(subject,
3466 match_start,
3467 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003468 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003469 for (int i = 1; i <= capture_count; i++) {
3470 int start = register_vector[i * 2];
3471 if (start >= 0) {
3472 int end = register_vector[i * 2 + 1];
3473 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003474 Handle<String> substring = isolate->factory()->NewSubString(subject,
3475 start,
3476 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003477 elements->set(i, *substring);
3478 } else {
3479 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003480 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003481 }
3482 }
3483 elements->set(capture_count + 1, Smi::FromInt(match_start));
3484 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003485 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003486 }
3487 // Swap register vectors, so the last successful match is in
3488 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003489 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003490 prev_register_vector = register_vector;
3491 register_vector = tmp;
3492
3493 if (match_end > match_start) {
3494 pos = match_end;
3495 } else {
3496 pos = match_end + 1;
3497 if (pos > subject_length) {
3498 break;
3499 }
3500 }
3501
3502 result = RegExpImpl::IrregexpExecOnce(regexp,
3503 subject,
3504 pos,
3505 register_vector);
3506 } while (result == RegExpImpl::RE_SUCCESS);
3507
3508 if (result != RegExpImpl::RE_EXCEPTION) {
3509 // Finished matching, with at least one match.
3510 if (match_end < subject_length) {
3511 ReplacementStringBuilder::AddSubjectSlice(builder,
3512 match_end,
3513 subject_length);
3514 }
3515
3516 int last_match_capture_count = (capture_count + 1) * 2;
3517 int last_match_array_size =
3518 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3519 last_match_array->EnsureSize(last_match_array_size);
3520 AssertNoAllocation no_gc;
3521 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3522 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3523 RegExpImpl::SetLastSubject(elements, *subject);
3524 RegExpImpl::SetLastInput(elements, *subject);
3525 for (int i = 0; i < last_match_capture_count; i++) {
3526 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3527 }
3528 return RegExpImpl::RE_SUCCESS;
3529 }
3530 }
3531 // No matches at all, return failure or exception result directly.
3532 return result;
3533}
3534
3535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003536static MaybeObject* Runtime_RegExpExecMultiple(RUNTIME_CALLING_CONVENTION) {
3537 RUNTIME_GET_ISOLATE;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003540
3541 CONVERT_ARG_CHECKED(String, subject, 1);
3542 if (!subject->IsFlat()) { FlattenString(subject); }
3543 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3544 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3545 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3546
3547 ASSERT(last_match_info->HasFastElements());
3548 ASSERT(regexp->GetFlags().is_global());
3549 Handle<FixedArray> result_elements;
3550 if (result_array->HasFastElements()) {
3551 result_elements =
3552 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3553 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003555 }
3556 FixedArrayBuilder builder(result_elements);
3557
3558 if (regexp->TypeTag() == JSRegExp::ATOM) {
3559 Handle<String> pattern(
3560 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003561 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003562 if (SearchStringMultiple(isolate, subject, pattern,
3563 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003564 return *builder.ToJSArray(result_array);
3565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003567 }
3568
3569 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3570
3571 RegExpImpl::IrregexpResult result;
3572 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 result = SearchRegExpNoCaptureMultiple(isolate,
3574 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003575 regexp,
3576 last_match_info,
3577 &builder);
3578 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003579 result = SearchRegExpMultiple(isolate,
3580 subject,
3581 regexp,
3582 last_match_info,
3583 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003584 }
3585 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003587 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3588 return Failure::Exception();
3589}
3590
3591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592static MaybeObject* Runtime_NumberToRadixString(RUNTIME_CALLING_CONVENTION) {
3593 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 NoHandleAllocation ha;
3595 ASSERT(args.length() == 2);
3596
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003597 // Fast case where the result is a one character string.
3598 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3599 int value = Smi::cast(args[0])->value();
3600 int radix = Smi::cast(args[1])->value();
3601 if (value >= 0 && value < radix) {
3602 RUNTIME_ASSERT(radix <= 36);
3603 // Character array used for conversion.
3604 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return isolate->heap()->
3606 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003607 }
3608 }
3609
3610 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 CONVERT_DOUBLE_CHECKED(value, args[0]);
3612 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 }
3615 if (isinf(value)) {
3616 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
3621 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3622 int radix = FastD2I(radix_number);
3623 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3624 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 MaybeObject* result =
3626 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 DeleteArray(str);
3628 return result;
3629}
3630
3631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632static MaybeObject* Runtime_NumberToFixed(RUNTIME_CALLING_CONVENTION) {
3633 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 NoHandleAllocation ha;
3635 ASSERT(args.length() == 2);
3636
3637 CONVERT_DOUBLE_CHECKED(value, args[0]);
3638 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 }
3641 if (isinf(value)) {
3642 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003645 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 }
3647 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3648 int f = FastD2I(f_number);
3649 RUNTIME_ASSERT(f >= 0);
3650 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003651 MaybeObject* res =
3652 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655}
3656
3657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658static MaybeObject* Runtime_NumberToExponential(RUNTIME_CALLING_CONVENTION) {
3659 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 NoHandleAllocation ha;
3661 ASSERT(args.length() == 2);
3662
3663 CONVERT_DOUBLE_CHECKED(value, args[0]);
3664 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003665 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 }
3667 if (isinf(value)) {
3668 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
3673 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3674 int f = FastD2I(f_number);
3675 RUNTIME_ASSERT(f >= -1 && f <= 20);
3676 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 MaybeObject* res =
3678 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003681}
3682
3683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003684static MaybeObject* Runtime_NumberToPrecision(RUNTIME_CALLING_CONVENTION) {
3685 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686 NoHandleAllocation ha;
3687 ASSERT(args.length() == 2);
3688
3689 CONVERT_DOUBLE_CHECKED(value, args[0]);
3690 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 }
3693 if (isinf(value)) {
3694 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3700 int f = FastD2I(f_number);
3701 RUNTIME_ASSERT(f >= 1 && f <= 21);
3702 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003703 MaybeObject* res =
3704 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707}
3708
3709
3710// Returns a single character string where first character equals
3711// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003713 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003714 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003715 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003716 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003718 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719}
3720
3721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3723 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003724 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 // Handle [] indexing on Strings
3726 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003727 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3728 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 }
3730
3731 // Handle [] indexing on String objects
3732 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003733 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3734 Handle<Object> result =
3735 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3736 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 }
3738
3739 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003740 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 return prototype->GetElement(index);
3742 }
3743
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003744 return GetElement(object, index);
3745}
3746
3747
lrn@chromium.org303ada72010-10-27 09:33:13 +00003748MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 return object->GetElement(index);
3750}
3751
3752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003753MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3754 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003755 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003759 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 isolate->factory()->NewTypeError("non_object_property_load",
3762 HandleVector(args, 2));
3763 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
3765
3766 // Check if the given key is an array index.
3767 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003768 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003770 }
3771
3772 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003773 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003775 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 bool has_pending_exception = false;
3778 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003779 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003781 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 }
3783
ager@chromium.org32912102009-01-16 10:38:43 +00003784 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 // the element if so.
3786 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003787 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 } else {
3789 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003790 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 }
3792}
3793
3794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795static MaybeObject* Runtime_GetProperty(RUNTIME_CALLING_CONVENTION) {
3796 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 NoHandleAllocation ha;
3798 ASSERT(args.length() == 2);
3799
3800 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003801 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804}
3805
3806
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003807// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808static MaybeObject* Runtime_KeyedGetProperty(RUNTIME_CALLING_CONVENTION) {
3809 RUNTIME_GET_ISOLATE;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003810 NoHandleAllocation ha;
3811 ASSERT(args.length() == 2);
3812
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003813 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003814 // itself.
3815 //
3816 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003817 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003818 // global proxy object never has properties. This is the case
3819 // because the global proxy object forwards everything to its hidden
3820 // prototype including local lookups.
3821 //
3822 // Additionally, we need to make sure that we do not cache results
3823 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003824 if (args[0]->IsJSObject() &&
3825 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003826 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003827 args[1]->IsString()) {
3828 JSObject* receiver = JSObject::cast(args[0]);
3829 String* key = String::cast(args[1]);
3830 if (receiver->HasFastProperties()) {
3831 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003832 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3834 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003835 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003836 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003838 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003839 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003840 LookupResult result;
3841 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003842 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003843 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003845 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003846 }
3847 } else {
3848 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003849 StringDictionary* dictionary = receiver->property_dictionary();
3850 int entry = dictionary->FindEntry(key);
3851 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003852 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003853 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003854 if (!receiver->IsGlobalObject()) return value;
3855 value = JSGlobalPropertyCell::cast(value)->value();
3856 if (!value->IsTheHole()) return value;
3857 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003858 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003859 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003860 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3861 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003862 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003863 Handle<String> str = args.at<String>(0);
3864 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003865 if (index >= 0 && index < str->length()) {
3866 Handle<Object> result = GetCharAt(str, index);
3867 return *result;
3868 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003869 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003870
3871 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872 return Runtime::GetObjectProperty(isolate,
3873 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003874 args.at<Object>(1));
3875}
3876
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003877// Implements part of 8.12.9 DefineOwnProperty.
3878// There are 3 cases that lead here:
3879// Step 4b - define a new accessor property.
3880// Steps 9c & 12 - replace an existing data property with an accessor property.
3881// Step 12 - update an existing accessor property with an accessor or generic
3882// descriptor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003883static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(
3884 RUNTIME_CALLING_CONVENTION) {
3885 RUNTIME_GET_ISOLATE;
ager@chromium.org5c838252010-02-19 08:53:10 +00003886 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003887 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3889 CONVERT_CHECKED(String, name, args[1]);
3890 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003891 Object* fun = args[3];
3892 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003893 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3894 int unchecked = flag_attr->value();
3895 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3896 RUNTIME_ASSERT(!obj->IsNull());
3897 LookupResult result;
3898 obj->LocalLookupRealNamedProperty(name, &result);
3899
3900 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3901 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3902 // delete it to avoid running into trouble in DefineAccessor, which
3903 // handles this incorrectly if the property is readonly (does nothing)
3904 if (result.IsProperty() &&
3905 (result.type() == FIELD || result.type() == NORMAL
3906 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003907 Object* ok;
3908 { MaybeObject* maybe_ok =
3909 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3910 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3911 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003912 }
3913 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3914}
3915
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003916// Implements part of 8.12.9 DefineOwnProperty.
3917// There are 3 cases that lead here:
3918// Step 4a - define a new data property.
3919// Steps 9b & 12 - replace an existing accessor property with a data property.
3920// Step 12 - update an existing data property with a data or generic
3921// descriptor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922static MaybeObject* Runtime_DefineOrRedefineDataProperty(
3923 RUNTIME_CALLING_CONVENTION) {
3924 RUNTIME_GET_ISOLATE;
ager@chromium.org5c838252010-02-19 08:53:10 +00003925 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003926 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003927 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3928 CONVERT_ARG_CHECKED(String, name, 1);
3929 Handle<Object> obj_value = args.at<Object>(2);
3930
3931 CONVERT_CHECKED(Smi, flag, args[3]);
3932 int unchecked = flag->value();
3933 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3934
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003935 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3936
3937 // Check if this is an element.
3938 uint32_t index;
3939 bool is_element = name->AsArrayIndex(&index);
3940
3941 // Special case for elements if any of the flags are true.
3942 // If elements are in fast case we always implicitly assume that:
3943 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3944 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3945 is_element) {
3946 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003947 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003948 // We do not need to do access checks here since these has already
3949 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003950 Handle<Object> proto(js_object->GetPrototype());
3951 // If proxy is detached, ignore the assignment. Alternatively,
3952 // we could throw an exception.
3953 if (proto->IsNull()) return *obj_value;
3954 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003955 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003956 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003957 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003958 // Make sure that we never go back to fast case.
3959 dictionary->set_requires_slow_elements();
3960 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003961 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003962 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003963 }
3964
ager@chromium.org5c838252010-02-19 08:53:10 +00003965 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003966 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003967
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003968 // To be compatible with safari we do not change the value on API objects
3969 // in defineProperty. Firefox disagrees here, and actually changes the value.
3970 if (result.IsProperty() &&
3971 (result.type() == CALLBACKS) &&
3972 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003973 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003974 }
3975
ager@chromium.org5c838252010-02-19 08:53:10 +00003976 // Take special care when attributes are different and there is already
3977 // a property. For simplicity we normalize the property which enables us
3978 // to not worry about changing the instance_descriptor and creating a new
3979 // map. The current version of SetObjectProperty does not handle attributes
3980 // correctly in the case where a property is a field and is reset with
3981 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003982 if (result.IsProperty() &&
3983 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003984 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003985 if (js_object->IsJSGlobalProxy()) {
3986 // Since the result is a property, the prototype will exist so
3987 // we don't have to check for null.
3988 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003989 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003990 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003991 // Use IgnoreAttributes version since a readonly property may be
3992 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003993 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3994 *obj_value,
3995 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003996 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 return Runtime::ForceSetObjectProperty(isolate,
3999 js_object,
4000 name,
4001 obj_value,
4002 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004003}
4004
4005
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4007 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004008 Handle<Object> key,
4009 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004010 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004011 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004015 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 isolate->factory()->NewTypeError("non_object_property_store",
4018 HandleVector(args, 2));
4019 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
4021
4022 // If the object isn't a JavaScript object, we ignore the store.
4023 if (!object->IsJSObject()) return *value;
4024
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004025 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 // Check if the given key is an array index.
4028 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004029 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4031 // of a string using [] notation. We need to support this too in
4032 // JavaScript.
4033 // In the case of a String object we just need to redirect the assignment to
4034 // the underlying string if the index is in range. Since the underlying
4035 // string does nothing with the assignment then we can ignore such
4036 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004037 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004041 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004042 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 return *value;
4044 }
4045
4046 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004047 Handle<Object> result;
4048 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004049 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004051 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004052 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004053 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004055 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 return *value;
4057 }
4058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 bool has_pending_exception = false;
4061 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4062 if (has_pending_exception) return Failure::Exception();
4063 Handle<String> name = Handle<String>::cast(converted);
4064
4065 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004066 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004068 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070}
4071
4072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004073MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4074 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004075 Handle<Object> key,
4076 Handle<Object> value,
4077 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004079
4080 // Check if the given key is an array index.
4081 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004082 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004083 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4084 // of a string using [] notation. We need to support this too in
4085 // JavaScript.
4086 // In the case of a String object we just need to redirect the assignment to
4087 // the underlying string if the index is in range. Since the underlying
4088 // string does nothing with the assignment then we can ignore such
4089 // assignments.
4090 if (js_object->IsStringObjectWithCharacterAt(index)) {
4091 return *value;
4092 }
4093
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004094 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004095 }
4096
4097 if (key->IsString()) {
4098 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004099 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004100 } else {
4101 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004102 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004103 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4104 *value,
4105 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004106 }
4107 }
4108
4109 // Call-back into JavaScript to convert the key to a string.
4110 bool has_pending_exception = false;
4111 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4112 if (has_pending_exception) return Failure::Exception();
4113 Handle<String> name = Handle<String>::cast(converted);
4114
4115 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004117 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004118 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004119 }
4120}
4121
4122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004123MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4124 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004125 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004127
4128 // Check if the given key is an array index.
4129 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004130 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004131 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4132 // characters of a string using [] notation. In the case of a
4133 // String object we just need to redirect the deletion to the
4134 // underlying string if the index is in range. Since the
4135 // underlying string does nothing with the deletion, we can ignore
4136 // such deletions.
4137 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004138 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004139 }
4140
4141 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4142 }
4143
4144 Handle<String> key_string;
4145 if (key->IsString()) {
4146 key_string = Handle<String>::cast(key);
4147 } else {
4148 // Call-back into JavaScript to convert the key to a string.
4149 bool has_pending_exception = false;
4150 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4151 if (has_pending_exception) return Failure::Exception();
4152 key_string = Handle<String>::cast(converted);
4153 }
4154
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004155 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004156 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4157}
4158
4159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160static MaybeObject* Runtime_SetProperty(RUNTIME_CALLING_CONVENTION) {
4161 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004163 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164
4165 Handle<Object> object = args.at<Object>(0);
4166 Handle<Object> key = args.at<Object>(1);
4167 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4169 RUNTIME_ASSERT(
4170 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004172 PropertyAttributes attributes =
4173 static_cast<PropertyAttributes>(unchecked_attributes);
4174
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004175 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004176 if (args.length() == 5) {
4177 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4178 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4179 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004180 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 return Runtime::SetObjectProperty(isolate,
4184 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004185 key,
4186 value,
4187 attributes,
4188 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189}
4190
4191
4192// Set a local property, even if it is READ_ONLY. If the property does not
4193// exist, it will be added with attributes NONE.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004194static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(
4195 RUNTIME_CALLING_CONVENTION) {
4196 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004198 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 CONVERT_CHECKED(JSObject, object, args[0]);
4200 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004201 // Compute attributes.
4202 PropertyAttributes attributes = NONE;
4203 if (args.length() == 4) {
4204 CONVERT_CHECKED(Smi, value_obj, args[3]);
4205 int unchecked_value = value_obj->value();
4206 // Only attribute bits should be set.
4207 RUNTIME_ASSERT(
4208 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4209 attributes = static_cast<PropertyAttributes>(unchecked_value);
4210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004212 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004213 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214}
4215
4216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217static MaybeObject* Runtime_DeleteProperty(RUNTIME_CALLING_CONVENTION) {
4218 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004220 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
4222 CONVERT_CHECKED(JSObject, object, args[0]);
4223 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004224 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004225 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004226 ? JSObject::STRICT_DELETION
4227 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228}
4229
4230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231static Object* HasLocalPropertyImplementation(Isolate* isolate,
4232 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004233 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004234 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004235 // Handle hidden prototypes. If there's a hidden prototype above this thing
4236 // then we have to check it for properties, because they are supposed to
4237 // look like they are on this object.
4238 Handle<Object> proto(object->GetPrototype());
4239 if (proto->IsJSObject() &&
4240 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 return HasLocalPropertyImplementation(isolate,
4242 Handle<JSObject>::cast(proto),
4243 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004246}
4247
4248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004249static MaybeObject* Runtime_HasLocalProperty(RUNTIME_CALLING_CONVENTION) {
4250 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251 NoHandleAllocation ha;
4252 ASSERT(args.length() == 2);
4253 CONVERT_CHECKED(String, key, args[1]);
4254
ager@chromium.org9085a012009-05-11 19:22:57 +00004255 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004257 if (obj->IsJSObject()) {
4258 JSObject* object = JSObject::cast(obj);
4259 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004261 // Slow case. Either it's not there or we have an interceptor. We should
4262 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 HandleScope scope(isolate);
4264 return HasLocalPropertyImplementation(isolate,
4265 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004266 Handle<String>(key));
4267 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 // Well, there is one exception: Handle [] on strings.
4269 uint32_t index;
4270 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004271 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004272 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004273 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274 }
4275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277}
4278
4279
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004280static MaybeObject* Runtime_HasProperty(RUNTIME_CALLING_CONVENTION) {
4281 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004282 NoHandleAllocation na;
4283 ASSERT(args.length() == 2);
4284
4285 // Only JS objects can have properties.
4286 if (args[0]->IsJSObject()) {
4287 JSObject* object = JSObject::cast(args[0]);
4288 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292}
4293
4294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295static MaybeObject* Runtime_HasElement(RUNTIME_CALLING_CONVENTION) {
4296 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation na;
4298 ASSERT(args.length() == 2);
4299
4300 // Only JS objects can have elements.
4301 if (args[0]->IsJSObject()) {
4302 JSObject* object = JSObject::cast(args[0]);
4303 CONVERT_CHECKED(Smi, index_obj, args[1]);
4304 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308}
4309
4310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004311static MaybeObject* Runtime_IsPropertyEnumerable(RUNTIME_CALLING_CONVENTION) {
4312 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004313 NoHandleAllocation ha;
4314 ASSERT(args.length() == 2);
4315
4316 CONVERT_CHECKED(JSObject, object, args[0]);
4317 CONVERT_CHECKED(String, key, args[1]);
4318
4319 uint32_t index;
4320 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 }
4323
ager@chromium.org870a0b62008-11-04 11:43:05 +00004324 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004325 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326}
4327
4328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329static MaybeObject* Runtime_GetPropertyNames(RUNTIME_CALLING_CONVENTION) {
4330 RUNTIME_GET_ISOLATE;
4331 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004333 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 return *GetKeysFor(object);
4335}
4336
4337
4338// Returns either a FixedArray as Runtime_GetPropertyNames,
4339// or, if the given object has an enum cache that contains
4340// all enumerable properties of the object and its prototypes
4341// have none, the map of the object. This is used to speed up
4342// the check for deletions during a for-in.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343static MaybeObject* Runtime_GetPropertyNamesFast(RUNTIME_CALLING_CONVENTION) {
4344 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 ASSERT(args.length() == 1);
4346
4347 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4348
4349 if (raw_object->IsSimpleEnum()) return raw_object->map();
4350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004351 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004353 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4354 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355
4356 // Test again, since cache may have been built by preceding call.
4357 if (object->IsSimpleEnum()) return object->map();
4358
4359 return *content;
4360}
4361
4362
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363// Find the length of the prototype chain that is to to handled as one. If a
4364// prototype object is hidden it is to be viewed as part of the the object it
4365// is prototype for.
4366static int LocalPrototypeChainLength(JSObject* obj) {
4367 int count = 1;
4368 Object* proto = obj->GetPrototype();
4369 while (proto->IsJSObject() &&
4370 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4371 count++;
4372 proto = JSObject::cast(proto)->GetPrototype();
4373 }
4374 return count;
4375}
4376
4377
4378// Return the names of the local named properties.
4379// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004380static MaybeObject* Runtime_GetLocalPropertyNames(RUNTIME_CALLING_CONVENTION) {
4381 RUNTIME_GET_ISOLATE;
4382 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004383 ASSERT(args.length() == 1);
4384 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386 }
4387 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4388
4389 // Skip the global proxy as it has no properties and always delegates to the
4390 // real global object.
4391 if (obj->IsJSGlobalProxy()) {
4392 // Only collect names if access is permitted.
4393 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 !isolate->MayNamedAccess(*obj,
4395 isolate->heap()->undefined_value(),
4396 v8::ACCESS_KEYS)) {
4397 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4398 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004399 }
4400 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4401 }
4402
4403 // Find the number of objects making up this.
4404 int length = LocalPrototypeChainLength(*obj);
4405
4406 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004407 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004408 int total_property_count = 0;
4409 Handle<JSObject> jsproto = obj;
4410 for (int i = 0; i < length; i++) {
4411 // Only collect names if access is permitted.
4412 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 !isolate->MayNamedAccess(*jsproto,
4414 isolate->heap()->undefined_value(),
4415 v8::ACCESS_KEYS)) {
4416 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4417 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004418 }
4419 int n;
4420 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4421 local_property_count[i] = n;
4422 total_property_count += n;
4423 if (i < length - 1) {
4424 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4425 }
4426 }
4427
4428 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004429 Handle<FixedArray> names =
4430 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004431
4432 // Get the property names.
4433 jsproto = obj;
4434 int proto_with_hidden_properties = 0;
4435 for (int i = 0; i < length; i++) {
4436 jsproto->GetLocalPropertyNames(*names,
4437 i == 0 ? 0 : local_property_count[i - 1]);
4438 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4439 proto_with_hidden_properties++;
4440 }
4441 if (i < length - 1) {
4442 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4443 }
4444 }
4445
4446 // Filter out name of hidden propeties object.
4447 if (proto_with_hidden_properties > 0) {
4448 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450 names->length() - proto_with_hidden_properties);
4451 int dest_pos = 0;
4452 for (int i = 0; i < total_property_count; i++) {
4453 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004455 continue;
4456 }
4457 names->set(dest_pos++, name);
4458 }
4459 }
4460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004461 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004462}
4463
4464
4465// Return the names of the local indexed properties.
4466// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004467static MaybeObject* Runtime_GetLocalElementNames(RUNTIME_CALLING_CONVENTION) {
4468 RUNTIME_GET_ISOLATE;
4469 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 ASSERT(args.length() == 1);
4471 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004473 }
4474 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4475
4476 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004478 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004480}
4481
4482
4483// Return information on whether an object has a named or indexed interceptor.
4484// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485static MaybeObject* Runtime_GetInterceptorInfo(RUNTIME_CALLING_CONVENTION) {
4486 RUNTIME_GET_ISOLATE;
4487 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004488 ASSERT(args.length() == 1);
4489 if (!args[0]->IsJSObject()) {
4490 return Smi::FromInt(0);
4491 }
4492 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4493
4494 int result = 0;
4495 if (obj->HasNamedInterceptor()) result |= 2;
4496 if (obj->HasIndexedInterceptor()) result |= 1;
4497
4498 return Smi::FromInt(result);
4499}
4500
4501
4502// Return property names from named interceptor.
4503// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(
4505 RUNTIME_CALLING_CONVENTION) {
4506 RUNTIME_GET_ISOLATE;
4507 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004508 ASSERT(args.length() == 1);
4509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4510
4511 if (obj->HasNamedInterceptor()) {
4512 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4513 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4514 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004516}
4517
4518
4519// Return element names from indexed interceptor.
4520// args[0]: object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521static MaybeObject* Runtime_GetIndexedInterceptorElementNames(
4522 RUNTIME_CALLING_CONVENTION) {
4523 RUNTIME_GET_ISOLATE;
4524 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004525 ASSERT(args.length() == 1);
4526 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4527
4528 if (obj->HasIndexedInterceptor()) {
4529 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4530 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4531 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004533}
4534
4535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536static MaybeObject* Runtime_LocalKeys(RUNTIME_CALLING_CONVENTION) {
4537 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004538 ASSERT_EQ(args.length(), 1);
4539 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004541 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004542
4543 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004544 // Do access checks before going to the global object.
4545 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004547 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4549 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004550 }
4551
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004552 Handle<Object> proto(object->GetPrototype());
4553 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004555 object = Handle<JSObject>::cast(proto);
4556 }
4557
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004558 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4559 LOCAL_ONLY);
4560 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4561 // property array and since the result is mutable we have to create
4562 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004563 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004564 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004565 for (int i = 0; i < length; i++) {
4566 Object* entry = contents->get(i);
4567 if (entry->IsString()) {
4568 copy->set(i, entry);
4569 } else {
4570 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571 HandleScope scope(isolate);
4572 Handle<Object> entry_handle(entry, isolate);
4573 Handle<Object> entry_str =
4574 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004575 copy->set(i, *entry_str);
4576 }
4577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004579}
4580
4581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582static MaybeObject* Runtime_GetArgumentsProperty(RUNTIME_CALLING_CONVENTION) {
4583 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 NoHandleAllocation ha;
4585 ASSERT(args.length() == 1);
4586
4587 // Compute the frame holding the arguments.
4588 JavaScriptFrameIterator it;
4589 it.AdvanceToArgumentsFrame();
4590 JavaScriptFrame* frame = it.frame();
4591
4592 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004593 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594
4595 // Try to convert the key to an index. If successful and within
4596 // index return the the argument from the frame.
4597 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004598 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599 return frame->GetParameter(index);
4600 }
4601
4602 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 bool exception = false;
4605 Handle<Object> converted =
4606 Execution::ToString(args.at<Object>(0), &exception);
4607 if (exception) return Failure::Exception();
4608 Handle<String> key = Handle<String>::cast(converted);
4609
4610 // Try to convert the string key into an array index.
4611 if (key->AsArrayIndex(&index)) {
4612 if (index < n) {
4613 return frame->GetParameter(index);
4614 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
4617 }
4618
4619 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4621 if (key->Equals(isolate->heap()->callee_symbol())) {
4622 Object* function = frame->function();
4623 if (function->IsJSFunction() &&
4624 JSFunction::cast(function)->shared()->strict_mode()) {
4625 return isolate->Throw(*isolate->factory()->NewTypeError(
4626 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4627 }
4628 return function;
4629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630
4631 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633}
4634
4635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636static MaybeObject* Runtime_ToFastProperties(RUNTIME_CALLING_CONVENTION) {
4637 RUNTIME_GET_ISOLATE;
4638 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004639
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004640 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004641 Handle<Object> object = args.at<Object>(0);
4642 if (object->IsJSObject()) {
4643 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004644 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004645 MaybeObject* ok = js_object->TransformToFastProperties(0);
4646 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004647 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004648 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004649 return *object;
4650}
4651
4652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004653static MaybeObject* Runtime_ToSlowProperties(RUNTIME_CALLING_CONVENTION) {
4654 RUNTIME_GET_ISOLATE;
4655 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004656
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004657 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004658 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004659 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004660 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004661 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004662 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004663 return *object;
4664}
4665
4666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667static MaybeObject* Runtime_ToBool(RUNTIME_CALLING_CONVENTION) {
4668 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 NoHandleAllocation ha;
4670 ASSERT(args.length() == 1);
4671
4672 return args[0]->ToBoolean();
4673}
4674
4675
4676// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4677// Possible optimizations: put the type string into the oddballs.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004678static MaybeObject* Runtime_Typeof(RUNTIME_CALLING_CONVENTION) {
4679 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 NoHandleAllocation ha;
4681
4682 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684 HeapObject* heap_obj = HeapObject::cast(obj);
4685
4686 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687 if (heap_obj->map()->is_undetectable()) {
4688 return isolate->heap()->undefined_symbol();
4689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690
4691 InstanceType instance_type = heap_obj->map()->instance_type();
4692 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004693 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694 }
4695
4696 switch (instance_type) {
4697 case ODDBALL_TYPE:
4698 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 }
4701 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 }
4704 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004705 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004706 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 default:
4709 // For any kind of object not handled above, the spec rule for
4710 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 }
4713}
4714
4715
lrn@chromium.org25156de2010-04-06 13:10:27 +00004716static bool AreDigits(const char*s, int from, int to) {
4717 for (int i = from; i < to; i++) {
4718 if (s[i] < '0' || s[i] > '9') return false;
4719 }
4720
4721 return true;
4722}
4723
4724
4725static int ParseDecimalInteger(const char*s, int from, int to) {
4726 ASSERT(to - from < 10); // Overflow is not possible.
4727 ASSERT(from < to);
4728 int d = s[from] - '0';
4729
4730 for (int i = from + 1; i < to; i++) {
4731 d = 10 * d + (s[i] - '0');
4732 }
4733
4734 return d;
4735}
4736
4737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004738static MaybeObject* Runtime_StringToNumber(RUNTIME_CALLING_CONVENTION) {
4739 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 NoHandleAllocation ha;
4741 ASSERT(args.length() == 1);
4742 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004743 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004744
4745 // Fast case: short integer or some sorts of junk values.
4746 int len = subject->length();
4747 if (subject->IsSeqAsciiString()) {
4748 if (len == 0) return Smi::FromInt(0);
4749
4750 char const* data = SeqAsciiString::cast(subject)->GetChars();
4751 bool minus = (data[0] == '-');
4752 int start_pos = (minus ? 1 : 0);
4753
4754 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004756 } else if (data[start_pos] > '9') {
4757 // Fast check for a junk value. A valid string may start from a
4758 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4759 // the 'I' character ('Infinity'). All of that have codes not greater than
4760 // '9' except 'I'.
4761 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004763 }
4764 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4765 // The maximal/minimal smi has 10 digits. If the string has less digits we
4766 // know it will fit into the smi-data type.
4767 int d = ParseDecimalInteger(data, start_pos, len);
4768 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004770 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004771 } else if (!subject->HasHashCode() &&
4772 len <= String::kMaxArrayIndexSize &&
4773 (len == 1 || data[0] != '0')) {
4774 // String hash is not calculated yet but all the data are present.
4775 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004776 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004777#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004778 subject->Hash(); // Force hash calculation.
4779 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4780 static_cast<int>(hash));
4781#endif
4782 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004783 }
4784 return Smi::FromInt(d);
4785 }
4786 }
4787
4788 // Slower case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004789 return isolate->heap()->NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793static MaybeObject* Runtime_StringFromCharCodeArray(
4794 RUNTIME_CALLING_CONVENTION) {
4795 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 NoHandleAllocation ha;
4797 ASSERT(args.length() == 1);
4798
4799 CONVERT_CHECKED(JSArray, codes, args[0]);
4800 int length = Smi::cast(codes->length())->value();
4801
4802 // Check if the string can be ASCII.
4803 int i;
4804 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 Object* element;
4806 { MaybeObject* maybe_element = codes->GetElement(i);
4807 // We probably can't get an exception here, but just in order to enforce
4808 // the checking of inputs in the runtime calls we check here.
4809 if (!maybe_element->ToObject(&element)) return maybe_element;
4810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4812 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4813 break;
4814 }
4815
lrn@chromium.org303ada72010-10-27 09:33:13 +00004816 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004820 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004821 }
4822
lrn@chromium.org303ada72010-10-27 09:33:13 +00004823 Object* object = NULL;
4824 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 String* result = String::cast(object);
4826 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004827 Object* element;
4828 { MaybeObject* maybe_element = codes->GetElement(i);
4829 if (!maybe_element->ToObject(&element)) return maybe_element;
4830 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004832 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 }
4834 return result;
4835}
4836
4837
4838// kNotEscaped is generated by the following:
4839//
4840// #!/bin/perl
4841// for (my $i = 0; $i < 256; $i++) {
4842// print "\n" if $i % 16 == 0;
4843// my $c = chr($i);
4844// my $escaped = 1;
4845// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4846// print $escaped ? "0, " : "1, ";
4847// }
4848
4849
4850static bool IsNotEscaped(uint16_t character) {
4851 // Only for 8 bit characters, the rest are always escaped (in a different way)
4852 ASSERT(character < 256);
4853 static const char kNotEscaped[256] = {
4854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4856 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4857 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4858 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4859 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4860 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4861 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4862 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4863 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4864 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4865 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4866 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 };
4871 return kNotEscaped[character] != 0;
4872}
4873
4874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875static MaybeObject* Runtime_URIEscape(RUNTIME_CALLING_CONVENTION) {
4876 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 const char hex_chars[] = "0123456789ABCDEF";
4878 NoHandleAllocation ha;
4879 ASSERT(args.length() == 1);
4880 CONVERT_CHECKED(String, source, args[0]);
4881
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004882 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883
4884 int escaped_length = 0;
4885 int length = source->length();
4886 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004887 Access<StringInputBuffer> buffer(
4888 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 buffer->Reset(source);
4890 while (buffer->has_more()) {
4891 uint16_t character = buffer->GetNext();
4892 if (character >= 256) {
4893 escaped_length += 6;
4894 } else if (IsNotEscaped(character)) {
4895 escaped_length++;
4896 } else {
4897 escaped_length += 3;
4898 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004899 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004900 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004901 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004902 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 return Failure::OutOfMemoryException();
4904 }
4905 }
4906 }
4907 // No length change implies no change. Return original string if no change.
4908 if (escaped_length == length) {
4909 return source;
4910 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 { MaybeObject* maybe_o =
4913 isolate->heap()->AllocateRawAsciiString(escaped_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 int dest_position = 0;
4918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 Access<StringInputBuffer> buffer(
4920 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 buffer->Rewind();
4922 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004923 uint16_t chr = buffer->GetNext();
4924 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004925 destination->Set(dest_position, '%');
4926 destination->Set(dest_position+1, 'u');
4927 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4928 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4929 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4930 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004932 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004933 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934 dest_position++;
4935 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004936 destination->Set(dest_position, '%');
4937 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4938 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 dest_position += 3;
4940 }
4941 }
4942 return destination;
4943}
4944
4945
4946static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4947 static const signed char kHexValue['g'] = {
4948 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4949 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4950 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4951 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4952 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, 10, 11, 12, 13, 14, 15 };
4955
4956 if (character1 > 'f') return -1;
4957 int hi = kHexValue[character1];
4958 if (hi == -1) return -1;
4959 if (character2 > 'f') return -1;
4960 int lo = kHexValue[character2];
4961 if (lo == -1) return -1;
4962 return (hi << 4) + lo;
4963}
4964
4965
ager@chromium.org870a0b62008-11-04 11:43:05 +00004966static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004967 int i,
4968 int length,
4969 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004970 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971 int32_t hi = 0;
4972 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 if (character == '%' &&
4974 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004975 source->Get(i + 1) == 'u' &&
4976 (hi = TwoDigitHex(source->Get(i + 2),
4977 source->Get(i + 3))) != -1 &&
4978 (lo = TwoDigitHex(source->Get(i + 4),
4979 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004980 *step = 6;
4981 return (hi << 8) + lo;
4982 } else if (character == '%' &&
4983 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 (lo = TwoDigitHex(source->Get(i + 1),
4985 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 *step = 3;
4987 return lo;
4988 } else {
4989 *step = 1;
4990 return character;
4991 }
4992}
4993
4994
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995static MaybeObject* Runtime_URIUnescape(RUNTIME_CALLING_CONVENTION) {
4996 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 NoHandleAllocation ha;
4998 ASSERT(args.length() == 1);
4999 CONVERT_CHECKED(String, source, args[0]);
5000
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005001 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005002
5003 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005004 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005
5006 int unescaped_length = 0;
5007 for (int i = 0; i < length; unescaped_length++) {
5008 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005009 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005010 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012 i += step;
5013 }
5014
5015 // No length change implies no change. Return original string if no change.
5016 if (unescaped_length == length)
5017 return source;
5018
lrn@chromium.org303ada72010-10-27 09:33:13 +00005019 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005020 { MaybeObject* maybe_o =
5021 ascii ?
5022 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5023 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005024 if (!maybe_o->ToObject(&o)) return maybe_o;
5025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005026 String* destination = String::cast(o);
5027
5028 int dest_position = 0;
5029 for (int i = 0; i < length; dest_position++) {
5030 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005031 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005032 i += step;
5033 }
5034 return destination;
5035}
5036
5037
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005038static const unsigned int kQuoteTableLength = 128u;
5039
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005040static const int kJsonQuotesCharactersPerEntry = 8;
5041static const char* const JsonQuotes =
5042 "\\u0000 \\u0001 \\u0002 \\u0003 "
5043 "\\u0004 \\u0005 \\u0006 \\u0007 "
5044 "\\b \\t \\n \\u000b "
5045 "\\f \\r \\u000e \\u000f "
5046 "\\u0010 \\u0011 \\u0012 \\u0013 "
5047 "\\u0014 \\u0015 \\u0016 \\u0017 "
5048 "\\u0018 \\u0019 \\u001a \\u001b "
5049 "\\u001c \\u001d \\u001e \\u001f "
5050 " ! \\\" # "
5051 "$ % & ' "
5052 "( ) * + "
5053 ", - . / "
5054 "0 1 2 3 "
5055 "4 5 6 7 "
5056 "8 9 : ; "
5057 "< = > ? "
5058 "@ A B C "
5059 "D E F G "
5060 "H I J K "
5061 "L M N O "
5062 "P Q R S "
5063 "T U V W "
5064 "X Y Z [ "
5065 "\\\\ ] ^ _ "
5066 "` a b c "
5067 "d e f g "
5068 "h i j k "
5069 "l m n o "
5070 "p q r s "
5071 "t u v w "
5072 "x y z { "
5073 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074
5075
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076// For a string that is less than 32k characters it should always be
5077// possible to allocate it in new space.
5078static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5079
5080
5081// Doing JSON quoting cannot make the string more than this many times larger.
5082static const int kJsonQuoteWorstCaseBlowup = 6;
5083
5084
5085// Covers the entire ASCII range (all other characters are unchanged by JSON
5086// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087static const byte JsonQuoteLengths[kQuoteTableLength] = {
5088 6, 6, 6, 6, 6, 6, 6, 6,
5089 2, 2, 2, 6, 2, 2, 6, 6,
5090 6, 6, 6, 6, 6, 6, 6, 6,
5091 6, 6, 6, 6, 6, 6, 6, 6,
5092 1, 1, 2, 1, 1, 1, 1, 1,
5093 1, 1, 1, 1, 1, 1, 1, 1,
5094 1, 1, 1, 1, 1, 1, 1, 1,
5095 1, 1, 1, 1, 1, 1, 1, 1,
5096 1, 1, 1, 1, 1, 1, 1, 1,
5097 1, 1, 1, 1, 1, 1, 1, 1,
5098 1, 1, 1, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 2, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104};
5105
5106
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005107template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005109
5110
5111template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5113 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114}
5115
5116
5117template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5119 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005120}
5121
5122
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005123template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5125 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005127 const Char* read_cursor = characters.start();
5128 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005129 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005130 int quoted_length = kSpaceForQuotes;
5131 while (read_cursor < end) {
5132 Char c = *(read_cursor++);
5133 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5134 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005135 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005136 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005137 }
5138 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005139 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5140 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005141 Object* new_object;
5142 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005143 return new_alloc;
5144 }
5145 StringType* new_string = StringType::cast(new_object);
5146
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005147 Char* write_cursor = reinterpret_cast<Char*>(
5148 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005149 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150 *(write_cursor++) = '"';
5151
5152 read_cursor = characters.start();
5153 while (read_cursor < end) {
5154 Char c = *(read_cursor++);
5155 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5156 *(write_cursor++) = c;
5157 } else {
5158 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5159 const char* replacement = JsonQuotes +
5160 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5161 for (int i = 0; i < len; i++) {
5162 *write_cursor++ = *replacement++;
5163 }
5164 }
5165 }
5166 *(write_cursor++) = '"';
5167 return new_string;
5168}
5169
5170
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172static MaybeObject* QuoteJsonString(Isolate* isolate,
5173 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005174 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005176 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005177 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5178 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005179 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005180 }
5181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5183 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005184 Object* new_object;
5185 if (!new_alloc->ToObject(&new_object)) {
5186 return new_alloc;
5187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005189 // Even if our string is small enough to fit in new space we still have to
5190 // handle it being allocated in old space as may happen in the third
5191 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5192 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 }
5195 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005197
5198 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5199 Char* write_cursor = reinterpret_cast<Char*>(
5200 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005201 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005202 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005203
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005204 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005205 const Char* end = read_cursor + length;
5206 while (read_cursor < end) {
5207 Char c = *(read_cursor++);
5208 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5209 *(write_cursor++) = c;
5210 } else {
5211 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5212 const char* replacement = JsonQuotes +
5213 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5214 write_cursor[0] = replacement[0];
5215 if (len > 1) {
5216 write_cursor[1] = replacement[1];
5217 if (len > 2) {
5218 ASSERT(len == 6);
5219 write_cursor[2] = replacement[2];
5220 write_cursor[3] = replacement[3];
5221 write_cursor[4] = replacement[4];
5222 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005223 }
5224 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005225 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 }
5227 }
5228 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005229
5230 int final_length = static_cast<int>(
5231 write_cursor - reinterpret_cast<Char*>(
5232 new_string->address() + SeqAsciiString::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005233 isolate->heap()->new_space()->ShrinkStringAtAllocationBoundary<StringType>(
5234 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005235 return new_string;
5236}
5237
5238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005239static MaybeObject* Runtime_QuoteJSONString(RUNTIME_CALLING_CONVENTION) {
5240 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241 NoHandleAllocation ha;
5242 CONVERT_CHECKED(String, str, args[0]);
5243 if (!str->IsFlat()) {
5244 MaybeObject* try_flatten = str->TryFlatten();
5245 Object* flat;
5246 if (!try_flatten->ToObject(&flat)) {
5247 return try_flatten;
5248 }
5249 str = String::cast(flat);
5250 ASSERT(str->IsFlat());
5251 }
5252 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005253 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5254 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005256 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5257 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005258 }
5259}
5260
5261
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005262static MaybeObject* Runtime_QuoteJSONStringComma(RUNTIME_CALLING_CONVENTION) {
5263 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005264 NoHandleAllocation ha;
5265 CONVERT_CHECKED(String, str, args[0]);
5266 if (!str->IsFlat()) {
5267 MaybeObject* try_flatten = str->TryFlatten();
5268 Object* flat;
5269 if (!try_flatten->ToObject(&flat)) {
5270 return try_flatten;
5271 }
5272 str = String::cast(flat);
5273 ASSERT(str->IsFlat());
5274 }
5275 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5277 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005278 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5280 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005281 }
5282}
5283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005284static MaybeObject* Runtime_StringParseInt(RUNTIME_CALLING_CONVENTION) {
5285 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286 NoHandleAllocation ha;
5287
5288 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005289 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005291 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005292
lrn@chromium.org25156de2010-04-06 13:10:27 +00005293 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5294 double value = StringToInt(s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005295 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005296}
5297
5298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005299static MaybeObject* Runtime_StringParseFloat(RUNTIME_CALLING_CONVENTION) {
5300 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005301 NoHandleAllocation ha;
5302 CONVERT_CHECKED(String, str, args[0]);
5303
5304 // ECMA-262 section 15.1.2.3, empty string is NaN
5305 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5306
5307 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005308 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005309}
5310
5311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005313MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005315 String* s,
5316 int length,
5317 int input_string_length,
5318 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005319 // We try this twice, once with the assumption that the result is no longer
5320 // than the input and, if that assumption breaks, again with the exact
5321 // length. This may not be pretty, but it is nicer than what was here before
5322 // and I hereby claim my vaffel-is.
5323 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 // Allocate the resulting string.
5325 //
5326 // NOTE: This assumes that the upper/lower case of an ascii
5327 // character is also ascii. This is currently the case, but it
5328 // might break in the future if we implement more context and locale
5329 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005330 Object* o;
5331 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005332 ? isolate->heap()->AllocateRawAsciiString(length)
5333 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005334 if (!maybe_o->ToObject(&o)) return maybe_o;
5335 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 String* result = String::cast(o);
5337 bool has_changed_character = false;
5338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005339 // Convert all characters to upper case, assuming that they will fit
5340 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 Access<StringInputBuffer> buffer(
5342 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005343 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005344 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005345 // We can assume that the string is not empty
5346 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005347 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005348 bool has_next = buffer->has_more();
5349 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005350 int char_length = mapping->get(current, next, chars);
5351 if (char_length == 0) {
5352 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005353 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005354 i++;
5355 } else if (char_length == 1) {
5356 // Common case: converting the letter resulted in one character.
5357 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005358 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359 has_changed_character = true;
5360 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005361 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005362 // We've assumed that the result would be as long as the
5363 // input but here is a character that converts to several
5364 // characters. No matter, we calculate the exact length
5365 // of the result and try the whole thing again.
5366 //
5367 // Note that this leaves room for optimization. We could just
5368 // memcpy what we already have to the result string. Also,
5369 // the result string is the last object allocated we could
5370 // "realloc" it and probably, in the vast majority of cases,
5371 // extend the existing string to be able to hold the full
5372 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005373 int next_length = 0;
5374 if (has_next) {
5375 next_length = mapping->get(next, 0, chars);
5376 if (next_length == 0) next_length = 1;
5377 }
5378 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379 while (buffer->has_more()) {
5380 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005381 // NOTE: we use 0 as the next character here because, while
5382 // the next character may affect what a character converts to,
5383 // it does not in any case affect the length of what it convert
5384 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385 int char_length = mapping->get(current, 0, chars);
5386 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005387 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005388 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005389 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005390 return Failure::OutOfMemoryException();
5391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005393 // Try again with the real length.
5394 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 } else {
5396 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005397 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 i++;
5399 }
5400 has_changed_character = true;
5401 }
5402 current = next;
5403 }
5404 if (has_changed_character) {
5405 return result;
5406 } else {
5407 // If we didn't actually change anything in doing the conversion
5408 // we simple return the result and let the converted string
5409 // become garbage; there is no reason to keep two identical strings
5410 // alive.
5411 return s;
5412 }
5413}
5414
5415
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005416namespace {
5417
lrn@chromium.org303ada72010-10-27 09:33:13 +00005418static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5419
5420
5421// Given a word and two range boundaries returns a word with high bit
5422// set in every byte iff the corresponding input byte was strictly in
5423// the range (m, n). All the other bits in the result are cleared.
5424// This function is only useful when it can be inlined and the
5425// boundaries are statically known.
5426// Requires: all bytes in the input word and the boundaries must be
5427// ascii (less than 0x7F).
5428static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5429 // Every byte in an ascii string is less than or equal to 0x7F.
5430 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5431 // Use strict inequalities since in edge cases the function could be
5432 // further simplified.
5433 ASSERT(0 < m && m < n && n < 0x7F);
5434 // Has high bit set in every w byte less than n.
5435 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5436 // Has high bit set in every w byte greater than m.
5437 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5438 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5439}
5440
5441
5442enum AsciiCaseConversion {
5443 ASCII_TO_LOWER,
5444 ASCII_TO_UPPER
5445};
5446
5447
5448template <AsciiCaseConversion dir>
5449struct FastAsciiConverter {
5450 static bool Convert(char* dst, char* src, int length) {
5451#ifdef DEBUG
5452 char* saved_dst = dst;
5453 char* saved_src = src;
5454#endif
5455 // We rely on the distance between upper and lower case letters
5456 // being a known power of 2.
5457 ASSERT('a' - 'A' == (1 << 5));
5458 // Boundaries for the range of input characters than require conversion.
5459 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5460 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5461 bool changed = false;
5462 char* const limit = src + length;
5463#ifdef V8_HOST_CAN_READ_UNALIGNED
5464 // Process the prefix of the input that requires no conversion one
5465 // (machine) word at a time.
5466 while (src <= limit - sizeof(uintptr_t)) {
5467 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5468 if (AsciiRangeMask(w, lo, hi) != 0) {
5469 changed = true;
5470 break;
5471 }
5472 *reinterpret_cast<uintptr_t*>(dst) = w;
5473 src += sizeof(uintptr_t);
5474 dst += sizeof(uintptr_t);
5475 }
5476 // Process the remainder of the input performing conversion when
5477 // required one word at a time.
5478 while (src <= limit - sizeof(uintptr_t)) {
5479 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5480 uintptr_t m = AsciiRangeMask(w, lo, hi);
5481 // The mask has high (7th) bit set in every byte that needs
5482 // conversion and we know that the distance between cases is
5483 // 1 << 5.
5484 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5485 src += sizeof(uintptr_t);
5486 dst += sizeof(uintptr_t);
5487 }
5488#endif
5489 // Process the last few bytes of the input (or the whole input if
5490 // unaligned access is not supported).
5491 while (src < limit) {
5492 char c = *src;
5493 if (lo < c && c < hi) {
5494 c ^= (1 << 5);
5495 changed = true;
5496 }
5497 *dst = c;
5498 ++src;
5499 ++dst;
5500 }
5501#ifdef DEBUG
5502 CheckConvert(saved_dst, saved_src, length, changed);
5503#endif
5504 return changed;
5505 }
5506
5507#ifdef DEBUG
5508 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5509 bool expected_changed = false;
5510 for (int i = 0; i < length; i++) {
5511 if (dst[i] == src[i]) continue;
5512 expected_changed = true;
5513 if (dir == ASCII_TO_LOWER) {
5514 ASSERT('A' <= src[i] && src[i] <= 'Z');
5515 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5516 } else {
5517 ASSERT(dir == ASCII_TO_UPPER);
5518 ASSERT('a' <= src[i] && src[i] <= 'z');
5519 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5520 }
5521 }
5522 ASSERT(expected_changed == changed);
5523 }
5524#endif
5525};
5526
5527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005528struct ToLowerTraits {
5529 typedef unibrow::ToLowercase UnibrowConverter;
5530
lrn@chromium.org303ada72010-10-27 09:33:13 +00005531 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005532};
5533
5534
5535struct ToUpperTraits {
5536 typedef unibrow::ToUppercase UnibrowConverter;
5537
lrn@chromium.org303ada72010-10-27 09:33:13 +00005538 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005539};
5540
5541} // namespace
5542
5543
5544template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005545MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005546 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005547 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005548 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005549 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005550 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005551 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005552
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005553 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005554 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005555 if (length == 0) return s;
5556
5557 // Simpler handling of ascii strings.
5558 //
5559 // NOTE: This assumes that the upper/lower case of an ascii
5560 // character is also ascii. This is currently the case, but it
5561 // might break in the future if we implement more context and locale
5562 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005563 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005564 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005565 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005566 if (!maybe_o->ToObject(&o)) return maybe_o;
5567 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005568 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005569 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005570 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005571 return has_changed_character ? result : s;
5572 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005573
lrn@chromium.org303ada72010-10-27 09:33:13 +00005574 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005575 { MaybeObject* maybe_answer =
5576 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005577 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5578 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 if (answer->IsSmi()) {
5580 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005581 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005582 ConvertCaseHelper(isolate,
5583 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005584 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5585 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005587 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005588}
5589
5590
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005591static MaybeObject* Runtime_StringToLowerCase(RUNTIME_CALLING_CONVENTION) {
5592 RUNTIME_GET_ISOLATE;
5593 return ConvertCase<ToLowerTraits>(
5594 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595}
5596
5597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598static MaybeObject* Runtime_StringToUpperCase(RUNTIME_CALLING_CONVENTION) {
5599 RUNTIME_GET_ISOLATE;
5600 return ConvertCase<ToUpperTraits>(
5601 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602}
5603
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005604
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005605static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5606 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5607}
5608
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005610static MaybeObject* Runtime_StringTrim(RUNTIME_CALLING_CONVENTION) {
5611 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005612 NoHandleAllocation ha;
5613 ASSERT(args.length() == 3);
5614
5615 CONVERT_CHECKED(String, s, args[0]);
5616 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5617 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5618
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005619 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005620 int length = s->length();
5621
5622 int left = 0;
5623 if (trimLeft) {
5624 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5625 left++;
5626 }
5627 }
5628
5629 int right = length;
5630 if (trimRight) {
5631 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5632 right--;
5633 }
5634 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005635 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005636}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005638
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005639template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005640void FindStringIndices(Isolate* isolate,
5641 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005642 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005643 ZoneList<int>* indices,
5644 unsigned int limit) {
5645 ASSERT(limit > 0);
5646 // Collect indices of pattern in subject, and the end-of-string index.
5647 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005649 int pattern_length = pattern.length();
5650 int index = 0;
5651 while (limit > 0) {
5652 index = search.Search(subject, index);
5653 if (index < 0) return;
5654 indices->Add(index);
5655 index += pattern_length;
5656 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005657 }
5658}
5659
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005660
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005661static MaybeObject* Runtime_StringSplit(RUNTIME_CALLING_CONVENTION) {
5662 RUNTIME_GET_ISOLATE;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005663 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005664 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005665 CONVERT_ARG_CHECKED(String, subject, 0);
5666 CONVERT_ARG_CHECKED(String, pattern, 1);
5667 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5668
5669 int subject_length = subject->length();
5670 int pattern_length = pattern->length();
5671 RUNTIME_ASSERT(pattern_length > 0);
5672
5673 // The limit can be very large (0xffffffffu), but since the pattern
5674 // isn't empty, we can never create more parts than ~half the length
5675 // of the subject.
5676
5677 if (!subject->IsFlat()) FlattenString(subject);
5678
5679 static const int kMaxInitialListCapacity = 16;
5680
5681 ZoneScope scope(DELETE_ON_EXIT);
5682
5683 // Find (up to limit) indices of separator and end-of-string in subject
5684 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5685 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005686 if (!pattern->IsFlat()) FlattenString(pattern);
5687
5688 // No allocation block.
5689 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005690 AssertNoAllocation nogc;
5691 if (subject->IsAsciiRepresentation()) {
5692 Vector<const char> subject_vector = subject->ToAsciiVector();
5693 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 FindStringIndices(isolate,
5695 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005696 pattern->ToAsciiVector(),
5697 &indices,
5698 limit);
5699 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005700 FindStringIndices(isolate,
5701 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005702 pattern->ToUC16Vector(),
5703 &indices,
5704 limit);
5705 }
5706 } else {
5707 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5708 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 FindStringIndices(isolate,
5710 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005711 pattern->ToAsciiVector(),
5712 &indices,
5713 limit);
5714 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005715 FindStringIndices(isolate,
5716 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005717 pattern->ToUC16Vector(),
5718 &indices,
5719 limit);
5720 }
5721 }
5722 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005723
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005724 if (static_cast<uint32_t>(indices.length()) < limit) {
5725 indices.Add(subject_length);
5726 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005727
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005728 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005729
5730 // Create JSArray of substrings separated by separator.
5731 int part_count = indices.length();
5732
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005734 result->set_length(Smi::FromInt(part_count));
5735
5736 ASSERT(result->HasFastElements());
5737
5738 if (part_count == 1 && indices.at(0) == subject_length) {
5739 FixedArray::cast(result->elements())->set(0, *subject);
5740 return *result;
5741 }
5742
5743 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5744 int part_start = 0;
5745 for (int i = 0; i < part_count; i++) {
5746 HandleScope local_loop_handle;
5747 int part_end = indices.at(i);
5748 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005750 elements->set(i, *substring);
5751 part_start = part_end + pattern_length;
5752 }
5753
5754 return *result;
5755}
5756
5757
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005758// Copies ascii characters to the given fixed array looking up
5759// one-char strings in the cache. Gives up on the first char that is
5760// not in the cache and fills the remainder with smi zeros. Returns
5761// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762static int CopyCachedAsciiCharsToArray(Heap* heap,
5763 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005764 FixedArray* elements,
5765 int length) {
5766 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005767 FixedArray* ascii_cache = heap->single_character_string_cache();
5768 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005769 int i;
5770 for (i = 0; i < length; ++i) {
5771 Object* value = ascii_cache->get(chars[i]);
5772 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005774 elements->set(i, value, SKIP_WRITE_BARRIER);
5775 }
5776 if (i < length) {
5777 ASSERT(Smi::FromInt(0) == 0);
5778 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5779 }
5780#ifdef DEBUG
5781 for (int j = 0; j < length; ++j) {
5782 Object* element = elements->get(j);
5783 ASSERT(element == Smi::FromInt(0) ||
5784 (element->IsString() && String::cast(element)->LooksValid()));
5785 }
5786#endif
5787 return i;
5788}
5789
5790
5791// Converts a String to JSArray.
5792// For example, "foo" => ["f", "o", "o"].
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793static MaybeObject* Runtime_StringToArray(RUNTIME_CALLING_CONVENTION) {
5794 RUNTIME_GET_ISOLATE;
5795 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005796 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005797 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005798 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005799
5800 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005801 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005802
5803 Handle<FixedArray> elements;
5804 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005805 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 { MaybeObject* maybe_obj =
5807 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005808 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005810 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005811
5812 Vector<const char> chars = s->ToAsciiVector();
5813 // Note, this will initialize all elements (not only the prefix)
5814 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5816 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005817 *elements,
5818 length);
5819
5820 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005821 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5822 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005823 }
5824 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005825 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005827 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5828 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005829 }
5830 }
5831
5832#ifdef DEBUG
5833 for (int i = 0; i < length; ++i) {
5834 ASSERT(String::cast(elements->get(i))->length() == 1);
5835 }
5836#endif
5837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005839}
5840
5841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842static MaybeObject* Runtime_NewStringWrapper(RUNTIME_CALLING_CONVENTION) {
5843 RUNTIME_GET_ISOLATE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005844 NoHandleAllocation ha;
5845 ASSERT(args.length() == 1);
5846 CONVERT_CHECKED(String, value, args[0]);
5847 return value->ToObject();
5848}
5849
5850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005852 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005854 return char_length == 0;
5855}
5856
5857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005858static MaybeObject* Runtime_NumberToString(RUNTIME_CALLING_CONVENTION) {
5859 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005860 NoHandleAllocation ha;
5861 ASSERT(args.length() == 1);
5862
5863 Object* number = args[0];
5864 RUNTIME_ASSERT(number->IsNumber());
5865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005866 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005867}
5868
5869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870static MaybeObject* Runtime_NumberToStringSkipCache(
5871 RUNTIME_CALLING_CONVENTION) {
5872 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +00005873 NoHandleAllocation ha;
5874 ASSERT(args.length() == 1);
5875
5876 Object* number = args[0];
5877 RUNTIME_ASSERT(number->IsNumber());
5878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005880}
5881
5882
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005883static MaybeObject* Runtime_NumberToInteger(RUNTIME_CALLING_CONVENTION) {
5884 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885 NoHandleAllocation ha;
5886 ASSERT(args.length() == 1);
5887
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005888 CONVERT_DOUBLE_CHECKED(number, args[0]);
5889
5890 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5891 if (number > 0 && number <= Smi::kMaxValue) {
5892 return Smi::FromInt(static_cast<int>(number));
5893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005894 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895}
5896
5897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898static MaybeObject* Runtime_NumberToIntegerMapMinusZero(
5899 RUNTIME_CALLING_CONVENTION) {
5900 RUNTIME_GET_ISOLATE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005901 NoHandleAllocation ha;
5902 ASSERT(args.length() == 1);
5903
5904 CONVERT_DOUBLE_CHECKED(number, args[0]);
5905
5906 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5907 if (number > 0 && number <= Smi::kMaxValue) {
5908 return Smi::FromInt(static_cast<int>(number));
5909 }
5910
5911 double double_value = DoubleToInteger(number);
5912 // Map both -0 and +0 to +0.
5913 if (double_value == 0) double_value = 0;
5914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005915 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005916}
5917
5918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919static MaybeObject* Runtime_NumberToJSUint32(RUNTIME_CALLING_CONVENTION) {
5920 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 1);
5923
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005924 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005925 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926}
5927
5928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005929static MaybeObject* Runtime_NumberToJSInt32(RUNTIME_CALLING_CONVENTION) {
5930 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
5933
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005934 CONVERT_DOUBLE_CHECKED(number, args[0]);
5935
5936 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5937 if (number > 0 && number <= Smi::kMaxValue) {
5938 return Smi::FromInt(static_cast<int>(number));
5939 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941}
5942
5943
ager@chromium.org870a0b62008-11-04 11:43:05 +00005944// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5945// a small integer.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946static MaybeObject* Runtime_NumberToSmi(RUNTIME_CALLING_CONVENTION) {
5947 RUNTIME_GET_ISOLATE;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005948 NoHandleAllocation ha;
5949 ASSERT(args.length() == 1);
5950
5951 Object* obj = args[0];
5952 if (obj->IsSmi()) {
5953 return obj;
5954 }
5955 if (obj->IsHeapNumber()) {
5956 double value = HeapNumber::cast(obj)->value();
5957 int int_value = FastD2I(value);
5958 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5959 return Smi::FromInt(int_value);
5960 }
5961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005962 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005963}
5964
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005966static MaybeObject* Runtime_AllocateHeapNumber(RUNTIME_CALLING_CONVENTION) {
5967 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005968 NoHandleAllocation ha;
5969 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005970 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005971}
5972
5973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974static MaybeObject* Runtime_NumberAdd(RUNTIME_CALLING_CONVENTION) {
5975 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976 NoHandleAllocation ha;
5977 ASSERT(args.length() == 2);
5978
5979 CONVERT_DOUBLE_CHECKED(x, args[0]);
5980 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982}
5983
5984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005985static MaybeObject* Runtime_NumberSub(RUNTIME_CALLING_CONVENTION) {
5986 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 NoHandleAllocation ha;
5988 ASSERT(args.length() == 2);
5989
5990 CONVERT_DOUBLE_CHECKED(x, args[0]);
5991 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993}
5994
5995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005996static MaybeObject* Runtime_NumberMul(RUNTIME_CALLING_CONVENTION) {
5997 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 NoHandleAllocation ha;
5999 ASSERT(args.length() == 2);
6000
6001 CONVERT_DOUBLE_CHECKED(x, args[0]);
6002 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006003 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004}
6005
6006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006007static MaybeObject* Runtime_NumberUnaryMinus(RUNTIME_CALLING_CONVENTION) {
6008 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009 NoHandleAllocation ha;
6010 ASSERT(args.length() == 1);
6011
6012 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006013 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014}
6015
6016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017static MaybeObject* Runtime_NumberAlloc(RUNTIME_CALLING_CONVENTION) {
6018 RUNTIME_GET_ISOLATE;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006019 NoHandleAllocation ha;
6020 ASSERT(args.length() == 0);
6021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006022 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006023}
6024
6025
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006026static MaybeObject* Runtime_NumberDiv(RUNTIME_CALLING_CONVENTION) {
6027 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 NoHandleAllocation ha;
6029 ASSERT(args.length() == 2);
6030
6031 CONVERT_DOUBLE_CHECKED(x, args[0]);
6032 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006033 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034}
6035
6036
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006037static MaybeObject* Runtime_NumberMod(RUNTIME_CALLING_CONVENTION) {
6038 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 NoHandleAllocation ha;
6040 ASSERT(args.length() == 2);
6041
6042 CONVERT_DOUBLE_CHECKED(x, args[0]);
6043 CONVERT_DOUBLE_CHECKED(y, args[1]);
6044
ager@chromium.org3811b432009-10-28 14:53:37 +00006045 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006046 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006047 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048}
6049
6050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006051static MaybeObject* Runtime_StringAdd(RUNTIME_CALLING_CONVENTION) {
6052 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 NoHandleAllocation ha;
6054 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055 CONVERT_CHECKED(String, str1, args[0]);
6056 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 isolate->counters()->string_add_runtime()->Increment();
6058 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059}
6060
6061
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006062template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006063static inline void StringBuilderConcatHelper(String* special,
6064 sinkchar* sink,
6065 FixedArray* fixed_array,
6066 int array_length) {
6067 int position = 0;
6068 for (int i = 0; i < array_length; i++) {
6069 Object* element = fixed_array->get(i);
6070 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006071 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006072 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006073 int pos;
6074 int len;
6075 if (encoded_slice > 0) {
6076 // Position and length encoded in one smi.
6077 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6078 len = StringBuilderSubstringLength::decode(encoded_slice);
6079 } else {
6080 // Position and length encoded in two smis.
6081 Object* obj = fixed_array->get(++i);
6082 ASSERT(obj->IsSmi());
6083 pos = Smi::cast(obj)->value();
6084 len = -encoded_slice;
6085 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006086 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006087 sink + position,
6088 pos,
6089 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006090 position += len;
6091 } else {
6092 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006093 int element_length = string->length();
6094 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006095 position += element_length;
6096 }
6097 }
6098}
6099
6100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006101static MaybeObject* Runtime_StringBuilderConcat(RUNTIME_CALLING_CONVENTION) {
6102 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006104 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006105 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006106 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006107 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006108 return Failure::OutOfMemoryException();
6109 }
6110 int array_length = Smi::cast(args[1])->value();
6111 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006112
6113 // This assumption is used by the slice encoding in one or two smis.
6114 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6115
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006116 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006118 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119 }
6120 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006121 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006122 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124
6125 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006126 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127 } else if (array_length == 1) {
6128 Object* first = fixed_array->get(0);
6129 if (first->IsString()) return first;
6130 }
6131
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006132 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006133 int position = 0;
6134 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006135 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006136 Object* elt = fixed_array->get(i);
6137 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006138 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006139 int smi_value = Smi::cast(elt)->value();
6140 int pos;
6141 int len;
6142 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006143 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006144 pos = StringBuilderSubstringPosition::decode(smi_value);
6145 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006146 } else {
6147 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006148 len = -smi_value;
6149 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006150 i++;
6151 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006152 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006153 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006154 Object* next_smi = fixed_array->get(i);
6155 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006157 }
6158 pos = Smi::cast(next_smi)->value();
6159 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006160 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006161 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006163 ASSERT(pos >= 0);
6164 ASSERT(len >= 0);
6165 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006166 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006167 }
6168 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169 } else if (elt->IsString()) {
6170 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006171 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006172 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006173 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006176 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006177 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006179 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006180 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006181 return Failure::OutOfMemoryException();
6182 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006183 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 }
6185
6186 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006190 { MaybeObject* maybe_object =
6191 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192 if (!maybe_object->ToObject(&object)) return maybe_object;
6193 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006194 SeqAsciiString* answer = SeqAsciiString::cast(object);
6195 StringBuilderConcatHelper(special,
6196 answer->GetChars(),
6197 fixed_array,
6198 array_length);
6199 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 { MaybeObject* maybe_object =
6202 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203 if (!maybe_object->ToObject(&object)) return maybe_object;
6204 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006205 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6206 StringBuilderConcatHelper(special,
6207 answer->GetChars(),
6208 fixed_array,
6209 array_length);
6210 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212}
6213
6214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215static MaybeObject* Runtime_StringBuilderJoin(RUNTIME_CALLING_CONVENTION) {
6216 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006217 NoHandleAllocation ha;
6218 ASSERT(args.length() == 3);
6219 CONVERT_CHECKED(JSArray, array, args[0]);
6220 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006221 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006222 return Failure::OutOfMemoryException();
6223 }
6224 int array_length = Smi::cast(args[1])->value();
6225 CONVERT_CHECKED(String, separator, args[2]);
6226
6227 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006229 }
6230 FixedArray* fixed_array = FixedArray::cast(array->elements());
6231 if (fixed_array->length() < array_length) {
6232 array_length = fixed_array->length();
6233 }
6234
6235 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006237 } else if (array_length == 1) {
6238 Object* first = fixed_array->get(0);
6239 if (first->IsString()) return first;
6240 }
6241
6242 int separator_length = separator->length();
6243 int max_nof_separators =
6244 (String::kMaxLength + separator_length - 1) / separator_length;
6245 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006246 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006247 return Failure::OutOfMemoryException();
6248 }
6249 int length = (array_length - 1) * separator_length;
6250 for (int i = 0; i < array_length; i++) {
6251 Object* element_obj = fixed_array->get(i);
6252 if (!element_obj->IsString()) {
6253 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006254 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006255 }
6256 String* element = String::cast(element_obj);
6257 int increment = element->length();
6258 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006260 return Failure::OutOfMemoryException();
6261 }
6262 length += increment;
6263 }
6264
6265 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 { MaybeObject* maybe_object =
6267 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006268 if (!maybe_object->ToObject(&object)) return maybe_object;
6269 }
6270 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6271
6272 uc16* sink = answer->GetChars();
6273#ifdef DEBUG
6274 uc16* end = sink + length;
6275#endif
6276
6277 String* first = String::cast(fixed_array->get(0));
6278 int first_length = first->length();
6279 String::WriteToFlat(first, sink, 0, first_length);
6280 sink += first_length;
6281
6282 for (int i = 1; i < array_length; i++) {
6283 ASSERT(sink + separator_length <= end);
6284 String::WriteToFlat(separator, sink, 0, separator_length);
6285 sink += separator_length;
6286
6287 String* element = String::cast(fixed_array->get(i));
6288 int element_length = element->length();
6289 ASSERT(sink + element_length <= end);
6290 String::WriteToFlat(element, sink, 0, element_length);
6291 sink += element_length;
6292 }
6293 ASSERT(sink == end);
6294
6295 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6296 return answer;
6297}
6298
6299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006300static MaybeObject* Runtime_NumberOr(RUNTIME_CALLING_CONVENTION) {
6301 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 NoHandleAllocation ha;
6303 ASSERT(args.length() == 2);
6304
6305 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6306 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006307 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308}
6309
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311static MaybeObject* Runtime_NumberAnd(RUNTIME_CALLING_CONVENTION) {
6312 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 NoHandleAllocation ha;
6314 ASSERT(args.length() == 2);
6315
6316 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6317 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006319}
6320
6321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322static MaybeObject* Runtime_NumberXor(RUNTIME_CALLING_CONVENTION) {
6323 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324 NoHandleAllocation ha;
6325 ASSERT(args.length() == 2);
6326
6327 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6328 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006329 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006330}
6331
6332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006333static MaybeObject* Runtime_NumberNot(RUNTIME_CALLING_CONVENTION) {
6334 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335 NoHandleAllocation ha;
6336 ASSERT(args.length() == 1);
6337
6338 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006339 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006340}
6341
6342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343static MaybeObject* Runtime_NumberShl(RUNTIME_CALLING_CONVENTION) {
6344 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345 NoHandleAllocation ha;
6346 ASSERT(args.length() == 2);
6347
6348 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6349 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006350 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351}
6352
6353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006354static MaybeObject* Runtime_NumberShr(RUNTIME_CALLING_CONVENTION) {
6355 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356 NoHandleAllocation ha;
6357 ASSERT(args.length() == 2);
6358
6359 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6360 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006361 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362}
6363
6364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006365static MaybeObject* Runtime_NumberSar(RUNTIME_CALLING_CONVENTION) {
6366 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 NoHandleAllocation ha;
6368 ASSERT(args.length() == 2);
6369
6370 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6371 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006373}
6374
6375
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006376static MaybeObject* Runtime_NumberEquals(RUNTIME_CALLING_CONVENTION) {
6377 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006378 NoHandleAllocation ha;
6379 ASSERT(args.length() == 2);
6380
6381 CONVERT_DOUBLE_CHECKED(x, args[0]);
6382 CONVERT_DOUBLE_CHECKED(y, args[1]);
6383 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6384 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6385 if (x == y) return Smi::FromInt(EQUAL);
6386 Object* result;
6387 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6388 result = Smi::FromInt(EQUAL);
6389 } else {
6390 result = Smi::FromInt(NOT_EQUAL);
6391 }
6392 return result;
6393}
6394
6395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006396static MaybeObject* Runtime_StringEquals(RUNTIME_CALLING_CONVENTION) {
6397 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 NoHandleAllocation ha;
6399 ASSERT(args.length() == 2);
6400
6401 CONVERT_CHECKED(String, x, args[0]);
6402 CONVERT_CHECKED(String, y, args[1]);
6403
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006404 bool not_equal = !x->Equals(y);
6405 // This is slightly convoluted because the value that signifies
6406 // equality is 0 and inequality is 1 so we have to negate the result
6407 // from String::Equals.
6408 ASSERT(not_equal == 0 || not_equal == 1);
6409 STATIC_CHECK(EQUAL == 0);
6410 STATIC_CHECK(NOT_EQUAL == 1);
6411 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412}
6413
6414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006415static MaybeObject* Runtime_NumberCompare(RUNTIME_CALLING_CONVENTION) {
6416 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417 NoHandleAllocation ha;
6418 ASSERT(args.length() == 3);
6419
6420 CONVERT_DOUBLE_CHECKED(x, args[0]);
6421 CONVERT_DOUBLE_CHECKED(y, args[1]);
6422 if (isnan(x) || isnan(y)) return args[2];
6423 if (x == y) return Smi::FromInt(EQUAL);
6424 if (isless(x, y)) return Smi::FromInt(LESS);
6425 return Smi::FromInt(GREATER);
6426}
6427
6428
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006429// Compare two Smis as if they were converted to strings and then
6430// compared lexicographically.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431static MaybeObject* Runtime_SmiLexicographicCompare(
6432 RUNTIME_CALLING_CONVENTION) {
6433 RUNTIME_GET_ISOLATE;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006434 NoHandleAllocation ha;
6435 ASSERT(args.length() == 2);
6436
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006437 // Extract the integer values from the Smis.
6438 CONVERT_CHECKED(Smi, x, args[0]);
6439 CONVERT_CHECKED(Smi, y, args[1]);
6440 int x_value = x->value();
6441 int y_value = y->value();
6442
6443 // If the integers are equal so are the string representations.
6444 if (x_value == y_value) return Smi::FromInt(EQUAL);
6445
6446 // If one of the integers are zero the normal integer order is the
6447 // same as the lexicographic order of the string representations.
6448 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6449
ager@chromium.org32912102009-01-16 10:38:43 +00006450 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006451 // smallest because the char code of '-' is less than the char code
6452 // of any digit. Otherwise, we make both values positive.
6453 if (x_value < 0 || y_value < 0) {
6454 if (y_value >= 0) return Smi::FromInt(LESS);
6455 if (x_value >= 0) return Smi::FromInt(GREATER);
6456 x_value = -x_value;
6457 y_value = -y_value;
6458 }
6459
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 // Arrays for the individual characters of the two Smis. Smis are
6461 // 31 bit integers and 10 decimal digits are therefore enough.
6462 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6463 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6464 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6465
6466
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006467 // Convert the integers to arrays of their decimal digits.
6468 int x_index = 0;
6469 int y_index = 0;
6470 while (x_value > 0) {
6471 x_elms[x_index++] = x_value % 10;
6472 x_value /= 10;
6473 }
6474 while (y_value > 0) {
6475 y_elms[y_index++] = y_value % 10;
6476 y_value /= 10;
6477 }
6478
6479 // Loop through the arrays of decimal digits finding the first place
6480 // where they differ.
6481 while (--x_index >= 0 && --y_index >= 0) {
6482 int diff = x_elms[x_index] - y_elms[y_index];
6483 if (diff != 0) return Smi::FromInt(diff);
6484 }
6485
6486 // If one array is a suffix of the other array, the longest array is
6487 // the representation of the largest of the Smis in the
6488 // lexicographic ordering.
6489 return Smi::FromInt(x_index - y_index);
6490}
6491
6492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006493static Object* StringInputBufferCompare(RuntimeState* state,
6494 String* x,
6495 String* y) {
6496 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6497 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006498 bufx.Reset(x);
6499 bufy.Reset(y);
6500 while (bufx.has_more() && bufy.has_more()) {
6501 int d = bufx.GetNext() - bufy.GetNext();
6502 if (d < 0) return Smi::FromInt(LESS);
6503 else if (d > 0) return Smi::FromInt(GREATER);
6504 }
6505
6506 // x is (non-trivial) prefix of y:
6507 if (bufy.has_more()) return Smi::FromInt(LESS);
6508 // y is prefix of x:
6509 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6510}
6511
6512
6513static Object* FlatStringCompare(String* x, String* y) {
6514 ASSERT(x->IsFlat());
6515 ASSERT(y->IsFlat());
6516 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6517 int prefix_length = x->length();
6518 if (y->length() < prefix_length) {
6519 prefix_length = y->length();
6520 equal_prefix_result = Smi::FromInt(GREATER);
6521 } else if (y->length() > prefix_length) {
6522 equal_prefix_result = Smi::FromInt(LESS);
6523 }
6524 int r;
6525 if (x->IsAsciiRepresentation()) {
6526 Vector<const char> x_chars = x->ToAsciiVector();
6527 if (y->IsAsciiRepresentation()) {
6528 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006529 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006530 } else {
6531 Vector<const uc16> y_chars = y->ToUC16Vector();
6532 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6533 }
6534 } else {
6535 Vector<const uc16> x_chars = x->ToUC16Vector();
6536 if (y->IsAsciiRepresentation()) {
6537 Vector<const char> y_chars = y->ToAsciiVector();
6538 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6539 } else {
6540 Vector<const uc16> y_chars = y->ToUC16Vector();
6541 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6542 }
6543 }
6544 Object* result;
6545 if (r == 0) {
6546 result = equal_prefix_result;
6547 } else {
6548 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6549 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006550 ASSERT(result ==
6551 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006552 return result;
6553}
6554
6555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556static MaybeObject* Runtime_StringCompare(RUNTIME_CALLING_CONVENTION) {
6557 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558 NoHandleAllocation ha;
6559 ASSERT(args.length() == 2);
6560
6561 CONVERT_CHECKED(String, x, args[0]);
6562 CONVERT_CHECKED(String, y, args[1]);
6563
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 // A few fast case tests before we flatten.
6567 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006568 if (y->length() == 0) {
6569 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006571 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 return Smi::FromInt(LESS);
6573 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006574
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006575 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006576 if (d < 0) return Smi::FromInt(LESS);
6577 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578
lrn@chromium.org303ada72010-10-27 09:33:13 +00006579 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006580 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006581 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006584 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006587 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006592static MaybeObject* Runtime_Math_acos(RUNTIME_CALLING_CONVENTION) {
6593 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006596 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597
6598 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006603static MaybeObject* Runtime_Math_asin(RUNTIME_CALLING_CONVENTION) {
6604 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605 NoHandleAllocation ha;
6606 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608
6609 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611}
6612
6613
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614static MaybeObject* Runtime_Math_atan(RUNTIME_CALLING_CONVENTION) {
6615 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 NoHandleAllocation ha;
6617 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006618 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619
6620 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622}
6623
6624
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006625static const double kPiDividedBy4 = 0.78539816339744830962;
6626
6627
6628static MaybeObject* Runtime_Math_atan2(RUNTIME_CALLING_CONVENTION) {
6629 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 NoHandleAllocation ha;
6631 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633
6634 CONVERT_DOUBLE_CHECKED(x, args[0]);
6635 CONVERT_DOUBLE_CHECKED(y, args[1]);
6636 double result;
6637 if (isinf(x) && isinf(y)) {
6638 // Make sure that the result in case of two infinite arguments
6639 // is a multiple of Pi / 4. The sign of the result is determined
6640 // by the first argument (x) and the sign of the second argument
6641 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 int multiplier = (x < 0) ? -1 : 1;
6643 if (y < 0) multiplier *= 3;
6644 result = multiplier * kPiDividedBy4;
6645 } else {
6646 result = atan2(x, y);
6647 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006648 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649}
6650
6651
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006652static MaybeObject* Runtime_Math_ceil(RUNTIME_CALLING_CONVENTION) {
6653 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 NoHandleAllocation ha;
6655 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657
6658 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006659 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006660}
6661
6662
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006663static MaybeObject* Runtime_Math_cos(RUNTIME_CALLING_CONVENTION) {
6664 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665 NoHandleAllocation ha;
6666 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006667 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668
6669 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671}
6672
6673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006674static MaybeObject* Runtime_Math_exp(RUNTIME_CALLING_CONVENTION) {
6675 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 NoHandleAllocation ha;
6677 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679
6680 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682}
6683
6684
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006685static MaybeObject* Runtime_Math_floor(RUNTIME_CALLING_CONVENTION) {
6686 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 NoHandleAllocation ha;
6688 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690
6691 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693}
6694
6695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696static MaybeObject* Runtime_Math_log(RUNTIME_CALLING_CONVENTION) {
6697 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 NoHandleAllocation ha;
6699 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006700 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701
6702 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704}
6705
6706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707static MaybeObject* Runtime_Math_pow(RUNTIME_CALLING_CONVENTION) {
6708 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 NoHandleAllocation ha;
6710 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712
6713 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006714
6715 // If the second argument is a smi, it is much faster to call the
6716 // custom powi() function than the generic pow().
6717 if (args[1]->IsSmi()) {
6718 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006720 }
6721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006723 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724}
6725
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006726// Fast version of Math.pow if we know that y is not an integer and
6727// y is not -0.5 or 0.5. Used as slowcase from codegen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006728static MaybeObject* Runtime_Math_pow_cfunction(RUNTIME_CALLING_CONVENTION) {
6729 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006730 NoHandleAllocation ha;
6731 ASSERT(args.length() == 2);
6732 CONVERT_DOUBLE_CHECKED(x, args[0]);
6733 CONVERT_DOUBLE_CHECKED(y, args[1]);
6734 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006735 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006736 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006737 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006738 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006739 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006740 }
6741}
6742
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744static MaybeObject* Runtime_RoundNumber(RUNTIME_CALLING_CONVENTION) {
6745 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006746 NoHandleAllocation ha;
6747 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006748 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006750 if (!args[0]->IsHeapNumber()) {
6751 // Must be smi. Return the argument unchanged for all the other types
6752 // to make fuzz-natives test happy.
6753 return args[0];
6754 }
6755
6756 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6757
6758 double value = number->value();
6759 int exponent = number->get_exponent();
6760 int sign = number->get_sign();
6761
6762 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6763 // should be rounded to 2^30, which is not smi.
6764 if (!sign && exponent <= kSmiValueSize - 3) {
6765 return Smi::FromInt(static_cast<int>(value + 0.5));
6766 }
6767
6768 // If the magnitude is big enough, there's no place for fraction part. If we
6769 // try to add 0.5 to this number, 1.0 will be added instead.
6770 if (exponent >= 52) {
6771 return number;
6772 }
6773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006775
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006776 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006777 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778}
6779
6780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781static MaybeObject* Runtime_Math_sin(RUNTIME_CALLING_CONVENTION) {
6782 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 NoHandleAllocation ha;
6784 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786
6787 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789}
6790
6791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006792static MaybeObject* Runtime_Math_sqrt(RUNTIME_CALLING_CONVENTION) {
6793 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 NoHandleAllocation ha;
6795 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797
6798 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800}
6801
6802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803static MaybeObject* Runtime_Math_tan(RUNTIME_CALLING_CONVENTION) {
6804 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 NoHandleAllocation ha;
6806 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808
6809 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811}
6812
6813
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006814static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006815 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6816 181, 212, 243, 273, 304, 334};
6817 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6818 182, 213, 244, 274, 305, 335};
6819
6820 year += month / 12;
6821 month %= 12;
6822 if (month < 0) {
6823 year--;
6824 month += 12;
6825 }
6826
6827 ASSERT(month >= 0);
6828 ASSERT(month < 12);
6829
6830 // year_delta is an arbitrary number such that:
6831 // a) year_delta = -1 (mod 400)
6832 // b) year + year_delta > 0 for years in the range defined by
6833 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6834 // Jan 1 1970. This is required so that we don't run into integer
6835 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006836 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006837 // operations.
6838 static const int year_delta = 399999;
6839 static const int base_day = 365 * (1970 + year_delta) +
6840 (1970 + year_delta) / 4 -
6841 (1970 + year_delta) / 100 +
6842 (1970 + year_delta) / 400;
6843
6844 int year1 = year + year_delta;
6845 int day_from_year = 365 * year1 +
6846 year1 / 4 -
6847 year1 / 100 +
6848 year1 / 400 -
6849 base_day;
6850
6851 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006852 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006853 }
6854
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006855 return day_from_year + day_from_month_leap[month] + day - 1;
6856}
6857
6858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006859static MaybeObject* Runtime_DateMakeDay(RUNTIME_CALLING_CONVENTION) {
6860 RUNTIME_GET_ISOLATE;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006861 NoHandleAllocation ha;
6862 ASSERT(args.length() == 3);
6863
6864 CONVERT_SMI_CHECKED(year, args[0]);
6865 CONVERT_SMI_CHECKED(month, args[1]);
6866 CONVERT_SMI_CHECKED(date, args[2]);
6867
6868 return Smi::FromInt(MakeDay(year, month, date));
6869}
6870
6871
6872static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6873static const int kDaysIn4Years = 4 * 365 + 1;
6874static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6875static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6876static const int kDays1970to2000 = 30 * 365 + 7;
6877static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6878 kDays1970to2000;
6879static const int kYearsOffset = 400000;
6880
6881static const char kDayInYear[] = {
6882 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6883 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6885 22, 23, 24, 25, 26, 27, 28,
6886 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6887 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6888 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6889 22, 23, 24, 25, 26, 27, 28, 29, 30,
6890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6891 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6893 22, 23, 24, 25, 26, 27, 28, 29, 30,
6894 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6895 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6896 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6897 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6898 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6899 22, 23, 24, 25, 26, 27, 28, 29, 30,
6900 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6901 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6902 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6903 22, 23, 24, 25, 26, 27, 28, 29, 30,
6904 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6905 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6906
6907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6910 22, 23, 24, 25, 26, 27, 28,
6911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6912 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6914 22, 23, 24, 25, 26, 27, 28, 29, 30,
6915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6916 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6918 22, 23, 24, 25, 26, 27, 28, 29, 30,
6919 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6920 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6921 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6922 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6923 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6924 22, 23, 24, 25, 26, 27, 28, 29, 30,
6925 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6926 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6927 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6928 22, 23, 24, 25, 26, 27, 28, 29, 30,
6929 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6930 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6931
6932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6935 22, 23, 24, 25, 26, 27, 28, 29,
6936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6937 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6939 22, 23, 24, 25, 26, 27, 28, 29, 30,
6940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6941 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6943 22, 23, 24, 25, 26, 27, 28, 29, 30,
6944 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6945 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6947 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6949 22, 23, 24, 25, 26, 27, 28, 29, 30,
6950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6951 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6952 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6953 22, 23, 24, 25, 26, 27, 28, 29, 30,
6954 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6955 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6956
6957 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6958 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6959 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6960 22, 23, 24, 25, 26, 27, 28,
6961 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6962 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6963 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6964 22, 23, 24, 25, 26, 27, 28, 29, 30,
6965 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6966 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6967 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6968 22, 23, 24, 25, 26, 27, 28, 29, 30,
6969 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6970 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6971 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6972 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6973 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6974 22, 23, 24, 25, 26, 27, 28, 29, 30,
6975 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6976 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6977 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6978 22, 23, 24, 25, 26, 27, 28, 29, 30,
6979 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6980 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6981
6982static const char kMonthInYear[] = {
6983 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,
6984 0, 0, 0, 0, 0, 0,
6985 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,
6986 1, 1, 1,
6987 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,
6988 2, 2, 2, 2, 2, 2,
6989 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,
6990 3, 3, 3, 3, 3,
6991 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,
6992 4, 4, 4, 4, 4, 4,
6993 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,
6994 5, 5, 5, 5, 5,
6995 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,
6996 6, 6, 6, 6, 6, 6,
6997 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,
6998 7, 7, 7, 7, 7, 7,
6999 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,
7000 8, 8, 8, 8, 8,
7001 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,
7002 9, 9, 9, 9, 9, 9,
7003 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7004 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7005 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7006 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7007
7008 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,
7009 0, 0, 0, 0, 0, 0,
7010 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,
7011 1, 1, 1,
7012 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,
7013 2, 2, 2, 2, 2, 2,
7014 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,
7015 3, 3, 3, 3, 3,
7016 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,
7017 4, 4, 4, 4, 4, 4,
7018 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,
7019 5, 5, 5, 5, 5,
7020 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,
7021 6, 6, 6, 6, 6, 6,
7022 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,
7023 7, 7, 7, 7, 7, 7,
7024 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,
7025 8, 8, 8, 8, 8,
7026 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,
7027 9, 9, 9, 9, 9, 9,
7028 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7029 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7030 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7031 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7032
7033 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,
7034 0, 0, 0, 0, 0, 0,
7035 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,
7036 1, 1, 1, 1,
7037 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,
7038 2, 2, 2, 2, 2, 2,
7039 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,
7040 3, 3, 3, 3, 3,
7041 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,
7042 4, 4, 4, 4, 4, 4,
7043 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,
7044 5, 5, 5, 5, 5,
7045 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,
7046 6, 6, 6, 6, 6, 6,
7047 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,
7048 7, 7, 7, 7, 7, 7,
7049 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,
7050 8, 8, 8, 8, 8,
7051 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,
7052 9, 9, 9, 9, 9, 9,
7053 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7054 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7055 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7056 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7057
7058 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,
7059 0, 0, 0, 0, 0, 0,
7060 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,
7061 1, 1, 1,
7062 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,
7063 2, 2, 2, 2, 2, 2,
7064 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,
7065 3, 3, 3, 3, 3,
7066 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,
7067 4, 4, 4, 4, 4, 4,
7068 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,
7069 5, 5, 5, 5, 5,
7070 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,
7071 6, 6, 6, 6, 6, 6,
7072 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,
7073 7, 7, 7, 7, 7, 7,
7074 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,
7075 8, 8, 8, 8, 8,
7076 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,
7077 9, 9, 9, 9, 9, 9,
7078 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7079 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7080 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7081 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7082
7083
7084// This function works for dates from 1970 to 2099.
7085static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007086 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007087#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007088 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007089#endif
7090
7091 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7092 date %= kDaysIn4Years;
7093
7094 month = kMonthInYear[date];
7095 day = kDayInYear[date];
7096
7097 ASSERT(MakeDay(year, month, day) == save_date);
7098}
7099
7100
7101static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007102 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007103#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007104 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007105#endif
7106
7107 date += kDaysOffset;
7108 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7109 date %= kDaysIn400Years;
7110
7111 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7112
7113 date--;
7114 int yd1 = date / kDaysIn100Years;
7115 date %= kDaysIn100Years;
7116 year += 100 * yd1;
7117
7118 date++;
7119 int yd2 = date / kDaysIn4Years;
7120 date %= kDaysIn4Years;
7121 year += 4 * yd2;
7122
7123 date--;
7124 int yd3 = date / 365;
7125 date %= 365;
7126 year += yd3;
7127
7128 bool is_leap = (!yd1 || yd2) && !yd3;
7129
7130 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007131 ASSERT(is_leap || (date >= 0));
7132 ASSERT((date < 365) || (is_leap && (date < 366)));
7133 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7134 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7135 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007136
7137 if (is_leap) {
7138 day = kDayInYear[2*365 + 1 + date];
7139 month = kMonthInYear[2*365 + 1 + date];
7140 } else {
7141 day = kDayInYear[date];
7142 month = kMonthInYear[date];
7143 }
7144
7145 ASSERT(MakeDay(year, month, day) == save_date);
7146}
7147
7148
7149static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007150 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007151 if (date >= 0 && date < 32 * kDaysIn4Years) {
7152 DateYMDFromTimeAfter1970(date, year, month, day);
7153 } else {
7154 DateYMDFromTimeSlow(date, year, month, day);
7155 }
7156}
7157
7158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007159static MaybeObject* Runtime_DateYMDFromTime(RUNTIME_CALLING_CONVENTION) {
7160 RUNTIME_GET_ISOLATE;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007161 NoHandleAllocation ha;
7162 ASSERT(args.length() == 2);
7163
7164 CONVERT_DOUBLE_CHECKED(t, args[0]);
7165 CONVERT_CHECKED(JSArray, res_array, args[1]);
7166
7167 int year, month, day;
7168 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 RUNTIME_ASSERT(res_array->elements()->map() ==
7171 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007172 FixedArray* elms = FixedArray::cast(res_array->elements());
7173 RUNTIME_ASSERT(elms->length() == 3);
7174
7175 elms->set(0, Smi::FromInt(year));
7176 elms->set(1, Smi::FromInt(month));
7177 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007179 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007180}
7181
7182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183static MaybeObject* Runtime_NewArgumentsFast(RUNTIME_CALLING_CONVENTION) {
7184 RUNTIME_GET_ISOLATE;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007185 NoHandleAllocation ha;
7186 ASSERT(args.length() == 3);
7187
7188 JSFunction* callee = JSFunction::cast(args[0]);
7189 Object** parameters = reinterpret_cast<Object**>(args[1]);
7190 const int length = Smi::cast(args[2])->value();
7191
lrn@chromium.org303ada72010-10-27 09:33:13 +00007192 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193 { MaybeObject* maybe_result =
7194 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007195 if (!maybe_result->ToObject(&result)) return maybe_result;
7196 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007197 // Allocate the elements if needed.
7198 if (length > 0) {
7199 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007200 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007202 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7203 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007204
7205 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007206 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007207 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007208 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007209
7210 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007211 for (int i = 0; i < length; i++) {
7212 array->set(i, *--parameters, mode);
7213 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007214 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007215 }
7216 return result;
7217}
7218
7219
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007220static MaybeObject* Runtime_NewClosure(RUNTIME_CALLING_CONVENTION) {
7221 RUNTIME_GET_ISOLATE;
7222 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007223 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007224 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007225 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007226 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007227
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007228 // Allocate global closures in old space and allocate local closures
7229 // in new space. Additionally pretenure closures that are assigned
7230 // directly to properties.
7231 pretenure = pretenure || (context->global_context() == *context);
7232 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007233 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7235 context,
7236 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 return *result;
7238}
7239
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007240static MaybeObject* Runtime_NewObjectFromBound(RUNTIME_CALLING_CONVENTION) {
7241 RUNTIME_GET_ISOLATE;
7242 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007243 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007244 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007245 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007246
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007247 // Second argument is either null or an array of bound arguments.
7248 FixedArray* bound_args = NULL;
7249 int bound_argc = 0;
7250 if (!args[1]->IsNull()) {
7251 CONVERT_ARG_CHECKED(JSArray, params, 1);
7252 RUNTIME_ASSERT(params->HasFastElements());
7253 bound_args = FixedArray::cast(params->elements());
7254 bound_argc = Smi::cast(params->length())->value();
7255 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007256
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007257 // Find frame containing arguments passed to the caller.
7258 JavaScriptFrameIterator it;
7259 JavaScriptFrame* frame = it.frame();
7260 ASSERT(!frame->is_optimized());
7261 it.AdvanceToArgumentsFrame();
7262 frame = it.frame();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007263 int argc = frame->ComputeParametersCount();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007264
7265 // Prepend bound arguments to caller's arguments.
7266 int total_argc = bound_argc + argc;
7267 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
7268 for (int i = 0; i < bound_argc; i++) {
7269 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007270 param_data[i] = val.location();
7271 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007272 for (int i = 0; i < argc; i++) {
7273 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7274 param_data[bound_argc + i] = val.location();
7275 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007276
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007277 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007278 Handle<Object> result =
7279 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007280 if (exception) {
7281 return Failure::Exception();
7282 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007283
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007284 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007285 return *result;
7286}
7287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289static void TrySettingInlineConstructStub(Isolate* isolate,
7290 Handle<JSFunction> function) {
7291 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007292 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007293 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007294 }
7295 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007296 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007297 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007298 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 function->shared()->set_construct_stub(
7300 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007301 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007302 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007303}
7304
7305
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306static MaybeObject* Runtime_NewObject(RUNTIME_CALLING_CONVENTION) {
7307 RUNTIME_GET_ISOLATE;
7308 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309 ASSERT(args.length() == 1);
7310
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007311 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007312
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007313 // If the constructor isn't a proper function we throw a type error.
7314 if (!constructor->IsJSFunction()) {
7315 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7316 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 isolate->factory()->NewTypeError("not_constructor", arguments);
7318 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007319 }
7320
7321 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007322
7323 // If function should not have prototype, construction is not allowed. In this
7324 // case generated code bailouts here, since function has no initial_map.
7325 if (!function->should_have_prototype()) {
7326 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7327 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 isolate->factory()->NewTypeError("not_constructor", arguments);
7329 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007330 }
7331
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007332#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007334 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 if (debug->StepInActive()) {
7336 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007337 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007338#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007340 if (function->has_initial_map()) {
7341 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342 // The 'Function' function ignores the receiver object when
7343 // called using 'new' and creates a new JSFunction object that
7344 // is returned. The receiver object is only used for error
7345 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007347 // allocate JSFunctions since it does not properly initialize
7348 // the shared part of the function. Since the receiver is
7349 // ignored anyway, we use the global object as the receiver
7350 // instead of a new JSFunction object. This way, errors are
7351 // reported the same way whether or not 'Function' is called
7352 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355 }
7356
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007357 // The function should be compiled for the optimization hints to be
7358 // available. We cannot use EnsureCompiled because that forces a
7359 // compilation through the shared function info which makes it
7360 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007362 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007363
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007364 if (!function->has_initial_map() &&
7365 shared->IsInobjectSlackTrackingInProgress()) {
7366 // The tracking is already in progress for another function. We can only
7367 // track one initial_map at a time, so we force the completion before the
7368 // function is called as a constructor for the first time.
7369 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007370 }
7371
7372 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7374 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007375 // Delay setting the stub if inobject slack tracking is in progress.
7376 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007378 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007380 isolate->counters()->constructed_objects()->Increment();
7381 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007382
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007383 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384}
7385
7386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387static MaybeObject* Runtime_FinalizeInstanceSize(RUNTIME_CALLING_CONVENTION) {
7388 RUNTIME_GET_ISOLATE;
7389 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007390 ASSERT(args.length() == 1);
7391
7392 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7393 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007397}
7398
7399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007400static MaybeObject* Runtime_LazyCompile(RUNTIME_CALLING_CONVENTION) {
7401 RUNTIME_GET_ISOLATE;
7402 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403 ASSERT(args.length() == 1);
7404
7405 Handle<JSFunction> function = args.at<JSFunction>(0);
7406#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007407 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007409 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410 PrintF("]\n");
7411 }
7412#endif
7413
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007414 // Compile the target function. Here we compile using CompileLazyInLoop in
7415 // order to get the optimized version. This helps code like delta-blue
7416 // that calls performance-critical routines through constructors. A
7417 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7418 // direct call. Since the in-loop tracking takes place through CallICs
7419 // this means that things called through constructors are never known to
7420 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007422 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423 return Failure::Exception();
7424 }
7425
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007426 // All done. Return the compiled code.
7427 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428 return function->code();
7429}
7430
7431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432static MaybeObject* Runtime_LazyRecompile(RUNTIME_CALLING_CONVENTION) {
7433 RUNTIME_GET_ISOLATE;
7434 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007435 ASSERT(args.length() == 1);
7436 Handle<JSFunction> function = args.at<JSFunction>(0);
7437 // If the function is not optimizable or debugger is active continue using the
7438 // code from the full compiler.
7439 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007440 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007441 if (FLAG_trace_opt) {
7442 PrintF("[failed to optimize ");
7443 function->PrintName();
7444 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7445 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007447 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007448 function->ReplaceCode(function->shared()->code());
7449 return function->code();
7450 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007451 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007452 return function->code();
7453 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007454 if (FLAG_trace_opt) {
7455 PrintF("[failed to optimize ");
7456 function->PrintName();
7457 PrintF(": optimized compilation failed]\n");
7458 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007459 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007460 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007461}
7462
7463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) {
7465 RUNTIME_GET_ISOLATE;
7466 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007467 ASSERT(args.length() == 1);
7468 RUNTIME_ASSERT(args[0]->IsSmi());
7469 Deoptimizer::BailoutType type =
7470 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7472 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007473 int frames = deoptimizer->output_count();
7474
7475 JavaScriptFrameIterator it;
7476 JavaScriptFrame* frame = NULL;
7477 for (int i = 0; i < frames; i++) {
7478 if (i != 0) it.Advance();
7479 frame = it.frame();
7480 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7481 }
7482 delete deoptimizer;
7483
7484 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007485 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 Handle<Object> arguments;
7487 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007489 if (arguments.is_null()) {
7490 // FunctionGetArguments can't throw an exception, so cast away the
7491 // doubt with an assert.
7492 arguments = Handle<Object>(
7493 Accessors::FunctionGetArguments(*function,
7494 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007495 ASSERT(*arguments != isolate->heap()->null_value());
7496 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007497 }
7498 frame->SetExpression(i, *arguments);
7499 }
7500 }
7501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007502 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007503 if (type == Deoptimizer::EAGER) {
7504 RUNTIME_ASSERT(function->IsOptimized());
7505 } else {
7506 RUNTIME_ASSERT(!function->IsOptimized());
7507 }
7508
7509 // Avoid doing too much work when running with --always-opt and keep
7510 // the optimized code around.
7511 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007513 }
7514
7515 // Count the number of optimized activations of the function.
7516 int activations = 0;
7517 while (!it.done()) {
7518 JavaScriptFrame* frame = it.frame();
7519 if (frame->is_optimized() && frame->function() == *function) {
7520 activations++;
7521 }
7522 it.Advance();
7523 }
7524
7525 // TODO(kasperl): For now, we cannot support removing the optimized
7526 // code when we have recursive invocations of the same function.
7527 if (activations == 0) {
7528 if (FLAG_trace_deopt) {
7529 PrintF("[removing optimized code for: ");
7530 function->PrintName();
7531 PrintF("]\n");
7532 }
7533 function->ReplaceCode(function->shared()->code());
7534 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007535 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007536}
7537
7538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539static MaybeObject* Runtime_NotifyOSR(RUNTIME_CALLING_CONVENTION) {
7540 RUNTIME_GET_ISOLATE;
7541 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007542 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007544}
7545
7546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547static MaybeObject* Runtime_DeoptimizeFunction(RUNTIME_CALLING_CONVENTION) {
7548 RUNTIME_GET_ISOLATE;
7549 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007550 ASSERT(args.length() == 1);
7551 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007552 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007553
7554 Deoptimizer::DeoptimizeFunction(*function);
7555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007557}
7558
7559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560static MaybeObject* Runtime_CompileForOnStackReplacement(
7561 RUNTIME_CALLING_CONVENTION) {
7562 RUNTIME_GET_ISOLATE;
7563 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007564 ASSERT(args.length() == 1);
7565 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7566
7567 // We're not prepared to handle a function with arguments object.
7568 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7569
7570 // We have hit a back edge in an unoptimized frame for a function that was
7571 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007573 // Keep track of whether we've succeeded in optimizing.
7574 bool succeeded = unoptimized->optimizable();
7575 if (succeeded) {
7576 // If we are trying to do OSR when there are already optimized
7577 // activations of the function, it means (a) the function is directly or
7578 // indirectly recursive and (b) an optimized invocation has been
7579 // deoptimized so that we are currently in an unoptimized activation.
7580 // Check for optimized activations of this function.
7581 JavaScriptFrameIterator it;
7582 while (succeeded && !it.done()) {
7583 JavaScriptFrame* frame = it.frame();
7584 succeeded = !frame->is_optimized() || frame->function() != *function;
7585 it.Advance();
7586 }
7587 }
7588
7589 int ast_id = AstNode::kNoNumber;
7590 if (succeeded) {
7591 // The top JS function is this one, the PC is somewhere in the
7592 // unoptimized code.
7593 JavaScriptFrameIterator it;
7594 JavaScriptFrame* frame = it.frame();
7595 ASSERT(frame->function() == *function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 ASSERT(frame->LookupCode(isolate) == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007597 ASSERT(unoptimized->contains(frame->pc()));
7598
7599 // Use linear search of the unoptimized code's stack check table to find
7600 // the AST id matching the PC.
7601 Address start = unoptimized->instruction_start();
7602 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007603 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007604 uint32_t table_length = Memory::uint32_at(table_cursor);
7605 table_cursor += kIntSize;
7606 for (unsigned i = 0; i < table_length; ++i) {
7607 // Table entries are (AST id, pc offset) pairs.
7608 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7609 if (pc_offset == target_pc_offset) {
7610 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7611 break;
7612 }
7613 table_cursor += 2 * kIntSize;
7614 }
7615 ASSERT(ast_id != AstNode::kNoNumber);
7616 if (FLAG_trace_osr) {
7617 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7618 function->PrintName();
7619 PrintF("]\n");
7620 }
7621
7622 // Try to compile the optimized code. A true return value from
7623 // CompileOptimized means that compilation succeeded, not necessarily
7624 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007625 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7626 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007627 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7628 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007629 if (data->OsrPcOffset()->value() >= 0) {
7630 if (FLAG_trace_osr) {
7631 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007632 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007633 }
7634 ASSERT(data->OsrAstId()->value() == ast_id);
7635 } else {
7636 // We may never generate the desired OSR entry if we emit an
7637 // early deoptimize.
7638 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007639 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007640 } else {
7641 succeeded = false;
7642 }
7643 }
7644
7645 // Revert to the original stack checks in the original unoptimized code.
7646 if (FLAG_trace_osr) {
7647 PrintF("[restoring original stack checks in ");
7648 function->PrintName();
7649 PrintF("]\n");
7650 }
7651 StackCheckStub check_stub;
7652 Handle<Code> check_code = check_stub.GetCode();
7653 Handle<Code> replacement_code(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007654 isolate->builtins()->builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007655 Deoptimizer::RevertStackCheckCode(*unoptimized,
7656 *check_code,
7657 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007658
7659 // Allow OSR only at nesting level zero again.
7660 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7661
7662 // If the optimization attempt succeeded, return the AST id tagged as a
7663 // smi. This tells the builtin that we need to translate the unoptimized
7664 // frame to an optimized one.
7665 if (succeeded) {
7666 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7667 return Smi::FromInt(ast_id);
7668 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007669 if (function->IsMarkedForLazyRecompilation()) {
7670 function->ReplaceCode(function->shared()->code());
7671 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007672 return Smi::FromInt(-1);
7673 }
7674}
7675
7676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) {
7678 RUNTIME_GET_ISOLATE;
7679 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007680 ASSERT(args.length() == 1);
7681 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7682 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7683}
7684
7685
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007686static MaybeObject* Runtime_GetConstructorDelegate(RUNTIME_CALLING_CONVENTION) {
7687 RUNTIME_GET_ISOLATE;
7688 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007689 ASSERT(args.length() == 1);
7690 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7691 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7692}
7693
7694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695static MaybeObject* Runtime_NewContext(RUNTIME_CALLING_CONVENTION) {
7696 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007698 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699
kasper.lund7276f142008-07-30 08:49:36 +00007700 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007701 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007702 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 { MaybeObject* maybe_result =
7704 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007705 if (!maybe_result->ToObject(&result)) return maybe_result;
7706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007708 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709
kasper.lund7276f142008-07-30 08:49:36 +00007710 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711}
7712
lrn@chromium.org303ada72010-10-27 09:33:13 +00007713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007714MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7715 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007716 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007717 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007718 Object* js_object = object;
7719 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007720 MaybeObject* maybe_js_object = js_object->ToObject();
7721 if (!maybe_js_object->ToObject(&js_object)) {
7722 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7723 return maybe_js_object;
7724 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 HandleScope scope(isolate);
7726 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007728 isolate->factory()->NewTypeError("with_expression",
7729 HandleVector(&handle, 1));
7730 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 }
7732 }
7733
lrn@chromium.org303ada72010-10-27 09:33:13 +00007734 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007735 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7736 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007737 if (!maybe_result->ToObject(&result)) return maybe_result;
7738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007740 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742
kasper.lund7276f142008-07-30 08:49:36 +00007743 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744}
7745
7746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747static MaybeObject* Runtime_PushContext(RUNTIME_CALLING_CONVENTION) {
7748 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007749 NoHandleAllocation ha;
7750 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007752}
7753
7754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007755static MaybeObject* Runtime_PushCatchContext(RUNTIME_CALLING_CONVENTION) {
7756 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007757 NoHandleAllocation ha;
7758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007760}
7761
7762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007763static MaybeObject* Runtime_DeleteContextSlot(RUNTIME_CALLING_CONVENTION) {
7764 RUNTIME_GET_ISOLATE;
7765 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 ASSERT(args.length() == 2);
7767
7768 CONVERT_ARG_CHECKED(Context, context, 0);
7769 CONVERT_ARG_CHECKED(String, name, 1);
7770
7771 int index;
7772 PropertyAttributes attributes;
7773 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007774 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007776 // If the slot was not found the result is true.
7777 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007778 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 }
7780
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007781 // If the slot was found in a context, it should be DONT_DELETE.
7782 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007784 }
7785
7786 // The slot was found in a JSObject, either a context extension object,
7787 // the global object, or an arguments object. Try to delete it
7788 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7789 // which allows deleting all parameters in functions that mention
7790 // 'arguments', we do this even for the case of slots found on an
7791 // arguments object. The slot was found on an arguments object if the
7792 // index is non-negative.
7793 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7794 if (index >= 0) {
7795 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7796 } else {
7797 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007799}
7800
7801
ager@chromium.orga1645e22009-09-09 19:27:10 +00007802// A mechanism to return a pair of Object pointers in registers (if possible).
7803// How this is achieved is calling convention-dependent.
7804// All currently supported x86 compiles uses calling conventions that are cdecl
7805// variants where a 64-bit value is returned in two 32-bit registers
7806// (edx:eax on ia32, r1:r0 on ARM).
7807// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7808// In Win64 calling convention, a struct of two pointers is returned in memory,
7809// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007810#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007811struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007812 MaybeObject* x;
7813 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007814};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007815
lrn@chromium.org303ada72010-10-27 09:33:13 +00007816static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007817 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007818 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7819 // In Win64 they are assigned to a hidden first argument.
7820 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007821}
7822#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007823typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007824static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007826 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007827}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007828#endif
7829
7830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831static inline MaybeObject* Unhole(Heap* heap,
7832 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007833 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7835 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007836 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837}
7838
7839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7841 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007842 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007843 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007844 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007845 JSFunction* context_extension_function =
7846 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007847 // If the holder isn't a context extension object, we just return it
7848 // as the receiver. This allows arguments objects to be used as
7849 // receivers, but only if they are put in the context scope chain
7850 // explicitly via a with-statement.
7851 Object* constructor = holder->map()->constructor();
7852 if (constructor != context_extension_function) return holder;
7853 // Fall back to using the global object as the receiver if the
7854 // property turns out to be a local variable allocated in a context
7855 // extension object - introduced via eval.
7856 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007857}
7858
7859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860static ObjectPair LoadContextSlotHelper(Arguments args,
7861 Isolate* isolate,
7862 bool throw_error) {
7863 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007864 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007866 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007870 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007871
7872 int index;
7873 PropertyAttributes attributes;
7874 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007875 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007877 // If the index is non-negative, the slot has been found in a local
7878 // variable or a parameter. Read it from the context object or the
7879 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007881 // If the "property" we were looking for is a local variable or an
7882 // argument in a context, the receiver is the global object; see
7883 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 JSObject* receiver =
7885 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007887 ? Context::cast(*holder)->get(index)
7888 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007889 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007890 }
7891
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007892 // If the holder is found, we read the property from it.
7893 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007894 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007895 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007896 JSObject* receiver;
7897 if (object->IsGlobalObject()) {
7898 receiver = GlobalObject::cast(object)->global_receiver();
7899 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007901 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007903 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007904 // No need to unhole the value here. This is taken care of by the
7905 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007906 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007907 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 }
7909
7910 if (throw_error) {
7911 // The property doesn't exist - throw exception.
7912 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 isolate->factory()->NewReferenceError("not_defined",
7914 HandleVector(&name, 1));
7915 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 } else {
7917 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007918 return MakePair(isolate->heap()->undefined_value(),
7919 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007920 }
7921}
7922
7923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007924static ObjectPair Runtime_LoadContextSlot(RUNTIME_CALLING_CONVENTION) {
7925 RUNTIME_GET_ISOLATE;
7926 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927}
7928
7929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930static ObjectPair Runtime_LoadContextSlotNoReferenceError(
7931 RUNTIME_CALLING_CONVENTION) {
7932 RUNTIME_GET_ISOLATE;
7933 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934}
7935
7936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007937static MaybeObject* Runtime_StoreContextSlot(RUNTIME_CALLING_CONVENTION) {
7938 RUNTIME_GET_ISOLATE;
7939 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007940 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007943 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007944 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007945 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7946 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7947 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007948 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007949
7950 int index;
7951 PropertyAttributes attributes;
7952 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007953 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954
7955 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007956 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957 // Ignore if read_only variable.
7958 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007959 // Context is a fixed array and set cannot fail.
7960 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007961 } else if (strict_mode == kStrictMode) {
7962 // Setting read only property in strict mode.
7963 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007964 isolate->factory()->NewTypeError("strict_cannot_assign",
7965 HandleVector(&name, 1));
7966 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007967 }
7968 } else {
7969 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007970 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007971 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007972 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007973 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007974 return Failure::Exception();
7975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007976 }
7977 return *value;
7978 }
7979
7980 // Slow case: The property is not in a FixedArray context.
7981 // It is either in an JSObject extension context or it was not found.
7982 Handle<JSObject> context_ext;
7983
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007984 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007985 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007986 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007987 } else {
7988 // The property was not found. It needs to be stored in the global context.
7989 ASSERT(attributes == ABSENT);
7990 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 }
7993
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007994 // Set the property, but ignore if read_only variable on the context
7995 // extension object itself.
7996 if ((attributes & READ_ONLY) == 0 ||
7997 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007998 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007999 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008000 SetProperty(context_ext, name, value, NONE, strict_mode));
8001 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008002 // Setting read only property in strict mode.
8003 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 isolate->factory()->NewTypeError(
8005 "strict_cannot_assign", HandleVector(&name, 1));
8006 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008007 }
8008 return *value;
8009}
8010
8011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012static MaybeObject* Runtime_Throw(RUNTIME_CALLING_CONVENTION) {
8013 RUNTIME_GET_ISOLATE;
8014 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 ASSERT(args.length() == 1);
8016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018}
8019
8020
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021static MaybeObject* Runtime_ReThrow(RUNTIME_CALLING_CONVENTION) {
8022 RUNTIME_GET_ISOLATE;
8023 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 ASSERT(args.length() == 1);
8025
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027}
8028
8029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030static MaybeObject* Runtime_PromoteScheduledException(
8031 RUNTIME_CALLING_CONVENTION) {
8032 RUNTIME_GET_ISOLATE;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008033 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008035}
8036
8037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008038static MaybeObject* Runtime_ThrowReferenceError(RUNTIME_CALLING_CONVENTION) {
8039 RUNTIME_GET_ISOLATE;
8040 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 ASSERT(args.length() == 1);
8042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008044 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008045 isolate->factory()->NewReferenceError("not_defined",
8046 HandleVector(&name, 1));
8047 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048}
8049
8050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008051static MaybeObject* Runtime_StackGuard(RUNTIME_CALLING_CONVENTION) {
8052 RUNTIME_GET_ISOLATE;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008053 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054
8055 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008056 if (isolate->stack_guard()->IsStackOverflow()) {
8057 NoHandleAllocation na;
8058 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008060
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008061 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008062}
8063
8064
8065// NOTE: These PrintXXX functions are defined for all builds (not just
8066// DEBUG builds) because we may want to be able to trace function
8067// calls in all modes.
8068static void PrintString(String* str) {
8069 // not uncommon to have empty strings
8070 if (str->length() > 0) {
8071 SmartPointer<char> s =
8072 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8073 PrintF("%s", *s);
8074 }
8075}
8076
8077
8078static void PrintObject(Object* obj) {
8079 if (obj->IsSmi()) {
8080 PrintF("%d", Smi::cast(obj)->value());
8081 } else if (obj->IsString() || obj->IsSymbol()) {
8082 PrintString(String::cast(obj));
8083 } else if (obj->IsNumber()) {
8084 PrintF("%g", obj->Number());
8085 } else if (obj->IsFailure()) {
8086 PrintF("<failure>");
8087 } else if (obj->IsUndefined()) {
8088 PrintF("<undefined>");
8089 } else if (obj->IsNull()) {
8090 PrintF("<null>");
8091 } else if (obj->IsTrue()) {
8092 PrintF("<true>");
8093 } else if (obj->IsFalse()) {
8094 PrintF("<false>");
8095 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008096 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 }
8098}
8099
8100
8101static int StackSize() {
8102 int n = 0;
8103 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8104 return n;
8105}
8106
8107
8108static void PrintTransition(Object* result) {
8109 // indentation
8110 { const int nmax = 80;
8111 int n = StackSize();
8112 if (n <= nmax)
8113 PrintF("%4d:%*s", n, n, "");
8114 else
8115 PrintF("%4d:%*s", n, nmax, "...");
8116 }
8117
8118 if (result == NULL) {
8119 // constructor calls
8120 JavaScriptFrameIterator it;
8121 JavaScriptFrame* frame = it.frame();
8122 if (frame->IsConstructor()) PrintF("new ");
8123 // function name
8124 Object* fun = frame->function();
8125 if (fun->IsJSFunction()) {
8126 PrintObject(JSFunction::cast(fun)->shared()->name());
8127 } else {
8128 PrintObject(fun);
8129 }
8130 // function arguments
8131 // (we are intentionally only printing the actually
8132 // supplied parameters, not all parameters required)
8133 PrintF("(this=");
8134 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008135 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136 for (int i = 0; i < length; i++) {
8137 PrintF(", ");
8138 PrintObject(frame->GetParameter(i));
8139 }
8140 PrintF(") {\n");
8141
8142 } else {
8143 // function result
8144 PrintF("} -> ");
8145 PrintObject(result);
8146 PrintF("\n");
8147 }
8148}
8149
8150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008151static MaybeObject* Runtime_TraceEnter(RUNTIME_CALLING_CONVENTION) {
8152 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008153 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008154 NoHandleAllocation ha;
8155 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008157}
8158
8159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160static MaybeObject* Runtime_TraceExit(RUNTIME_CALLING_CONVENTION) {
8161 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162 NoHandleAllocation ha;
8163 PrintTransition(args[0]);
8164 return args[0]; // return TOS
8165}
8166
8167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008168static MaybeObject* Runtime_DebugPrint(RUNTIME_CALLING_CONVENTION) {
8169 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008170 NoHandleAllocation ha;
8171 ASSERT(args.length() == 1);
8172
8173#ifdef DEBUG
8174 if (args[0]->IsString()) {
8175 // If we have a string, assume it's a code "marker"
8176 // and print some interesting cpu debugging info.
8177 JavaScriptFrameIterator it;
8178 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008179 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8180 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181 } else {
8182 PrintF("DebugPrint: ");
8183 }
8184 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008185 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008186 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008187 HeapObject::cast(args[0])->map()->Print();
8188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008189#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008190 // ShortPrint is available in release mode. Print is not.
8191 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008192#endif
8193 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008194 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195
8196 return args[0]; // return TOS
8197}
8198
8199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200static MaybeObject* Runtime_DebugTrace(RUNTIME_CALLING_CONVENTION) {
8201 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008202 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 isolate->PrintStack();
8205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206}
8207
8208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209static MaybeObject* Runtime_DateCurrentTime(RUNTIME_CALLING_CONVENTION) {
8210 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008212 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213
8214 // According to ECMA-262, section 15.9.1, page 117, the precision of
8215 // the number in a Date object representing a particular instant in
8216 // time is milliseconds. Therefore, we floor the result of getting
8217 // the OS time.
8218 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008220}
8221
8222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223static MaybeObject* Runtime_DateParseString(RUNTIME_CALLING_CONVENTION) {
8224 RUNTIME_GET_ISOLATE;
8225 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008226 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008228 CONVERT_ARG_CHECKED(String, str, 0);
8229 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008231 CONVERT_ARG_CHECKED(JSArray, output, 1);
8232 RUNTIME_ASSERT(output->HasFastElements());
8233
8234 AssertNoAllocation no_allocation;
8235
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008236 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008237 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8238 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008239 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008240 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008242 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008243 result = DateParser::Parse(str->ToUC16Vector(), output_array);
8244 }
8245
8246 if (result) {
8247 return *output;
8248 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 }
8251}
8252
8253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254static MaybeObject* Runtime_DateLocalTimezone(RUNTIME_CALLING_CONVENTION) {
8255 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008256 NoHandleAllocation ha;
8257 ASSERT(args.length() == 1);
8258
8259 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008260 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262}
8263
8264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008265static MaybeObject* Runtime_DateLocalTimeOffset(RUNTIME_CALLING_CONVENTION) {
8266 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008268 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271}
8272
8273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274static MaybeObject* Runtime_DateDaylightSavingsOffset(
8275 RUNTIME_CALLING_CONVENTION) {
8276 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277 NoHandleAllocation ha;
8278 ASSERT(args.length() == 1);
8279
8280 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282}
8283
8284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285static MaybeObject* Runtime_GlobalReceiver(RUNTIME_CALLING_CONVENTION) {
8286 RUNTIME_GET_ISOLATE;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008287 ASSERT(args.length() == 1);
8288 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008290 return JSGlobalObject::cast(global)->global_receiver();
8291}
8292
8293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294static MaybeObject* Runtime_ParseJson(RUNTIME_CALLING_CONVENTION) {
8295 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008296 ASSERT_EQ(1, args.length());
8297 CONVERT_ARG_CHECKED(String, source, 0);
8298
8299 Handle<Object> result = JsonParser::Parse(source);
8300 if (result.is_null()) {
8301 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008303 return Failure::Exception();
8304 }
8305 return *result;
8306}
8307
8308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309static MaybeObject* Runtime_CompileString(RUNTIME_CALLING_CONVENTION) {
8310 RUNTIME_GET_ISOLATE;
8311 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008312 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008313 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008314
ager@chromium.org381abbb2009-02-25 13:23:22 +00008315 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008317 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8318 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008319 true,
8320 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008321 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8324 context,
8325 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 return *fun;
8327}
8328
8329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330static ObjectPair CompileGlobalEval(Isolate* isolate,
8331 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008332 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008333 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008334 // Deal with a normal eval call with a string argument. Compile it
8335 // and return the compiled function bound in the local context.
8336 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8337 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008338 Handle<Context>(isolate->context()),
8339 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008340 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008341 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008342 Handle<JSFunction> compiled =
8343 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8344 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008345 return MakePair(*compiled, *receiver);
8346}
8347
8348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349static ObjectPair Runtime_ResolvePossiblyDirectEval(
8350 RUNTIME_CALLING_CONVENTION) {
8351 RUNTIME_GET_ISOLATE;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008352 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008355 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008356 Handle<Object> receiver; // Will be overwritten.
8357
8358 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008359 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008360#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008361 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008362 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008363 StackFrameLocator locator;
8364 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008365 ASSERT(Context::cast(frame->context()) == *context);
8366#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008367
8368 // Find where the 'eval' symbol is bound. It is unaliased only if
8369 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008370 int index = -1;
8371 PropertyAttributes attributes = ABSENT;
8372 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8374 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008375 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008376 // Stop search when eval is found or when the global context is
8377 // reached.
8378 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008379 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008380 context = Handle<Context>(Context::cast(context->closure()->context()),
8381 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008382 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008383 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008384 }
8385 }
8386
iposva@chromium.org245aa852009-02-10 00:49:54 +00008387 // If eval could not be resolved, it has been deleted and we need to
8388 // throw a reference error.
8389 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008391 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008392 isolate->factory()->NewReferenceError("not_defined",
8393 HandleVector(&name, 1));
8394 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008395 }
8396
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008397 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008398 // 'eval' is not bound in the global context. Just call the function
8399 // with the given arguments. This is not necessarily the global eval.
8400 if (receiver->IsContext()) {
8401 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008402 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008403 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 receiver = Handle<JSObject>(
8405 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008406 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008407 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008408 }
8409
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008410 // 'eval' is bound in the global context, but it may have been overwritten.
8411 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008413 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 return MakePair(*callee,
8415 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008416 }
8417
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008418 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 return CompileGlobalEval(isolate,
8420 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008421 args.at<Object>(2),
8422 static_cast<StrictModeFlag>(
8423 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008424}
8425
8426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(
8428 RUNTIME_CALLING_CONVENTION) {
8429 RUNTIME_GET_ISOLATE;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008430 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008433 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008434
8435 // 'eval' is bound in the global context, but it may have been overwritten.
8436 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008438 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 return MakePair(*callee,
8440 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008441 }
8442
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008443 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008444 return CompileGlobalEval(isolate,
8445 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008446 args.at<Object>(2),
8447 static_cast<StrictModeFlag>(
8448 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008449}
8450
8451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452static MaybeObject* Runtime_SetNewFunctionAttributes(
8453 RUNTIME_CALLING_CONVENTION) {
8454 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008455 // This utility adjusts the property attributes for newly created Function
8456 // object ("new Function(...)") by changing the map.
8457 // All it does is changing the prototype property to enumerable
8458 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460 ASSERT(args.length() == 1);
8461 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008462
8463 Handle<Map> map = func->shared()->strict_mode()
8464 ? isolate->strict_mode_function_instance_map()
8465 : isolate->function_instance_map();
8466
8467 ASSERT(func->map()->instance_type() == map->instance_type());
8468 ASSERT(func->map()->instance_size() == map->instance_size());
8469 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008470 return *func;
8471}
8472
8473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008474static MaybeObject* Runtime_AllocateInNewSpace(RUNTIME_CALLING_CONVENTION) {
8475 RUNTIME_GET_ISOLATE;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008476 // Allocate a block of memory in NewSpace (filled with a filler).
8477 // Use as fallback for allocation in generated code when NewSpace
8478 // is full.
8479 ASSERT(args.length() == 1);
8480 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8481 int size = size_smi->value();
8482 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8483 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 Heap* heap = isolate->heap();
8485 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008486 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008487 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008489 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008491 }
8492 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008493 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008494}
8495
8496
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008497// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008498// array. Returns true if the element was pushed on the stack and
8499// false otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500static MaybeObject* Runtime_PushIfAbsent(RUNTIME_CALLING_CONVENTION) {
8501 RUNTIME_GET_ISOLATE;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008502 ASSERT(args.length() == 2);
8503 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008504 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008505 RUNTIME_ASSERT(array->HasFastElements());
8506 int length = Smi::cast(array->length())->value();
8507 FixedArray* elements = FixedArray::cast(array->elements());
8508 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008509 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008510 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008511 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008512 // Strict not needed. Used for cycle detection in Array join implementation.
8513 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8514 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008517 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008518}
8519
8520
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008521/**
8522 * A simple visitor visits every element of Array's.
8523 * The backend storage can be a fixed array for fast elements case,
8524 * or a dictionary for sparse array. Since Dictionary is a subtype
8525 * of FixedArray, the class can be used by both fast and slow cases.
8526 * The second parameter of the constructor, fast_elements, specifies
8527 * whether the storage is a FixedArray or Dictionary.
8528 *
8529 * An index limit is used to deal with the situation that a result array
8530 * length overflows 32-bit non-negative integer.
8531 */
8532class ArrayConcatVisitor {
8533 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008534 ArrayConcatVisitor(Isolate* isolate,
8535 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008536 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008537 isolate_(isolate),
8538 storage_(Handle<FixedArray>::cast(
8539 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008540 index_offset_(0u),
8541 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008542
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008543 ~ArrayConcatVisitor() {
8544 clear_storage();
8545 }
8546
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008547 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008548 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008549 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008550
8551 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008552 if (index < static_cast<uint32_t>(storage_->length())) {
8553 storage_->set(index, *elm);
8554 return;
8555 }
8556 // Our initial estimate of length was foiled, possibly by
8557 // getters on the arrays increasing the length of later arrays
8558 // during iteration.
8559 // This shouldn't happen in anything but pathological cases.
8560 SetDictionaryMode(index);
8561 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008562 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008563 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008564 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008565 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008567 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008568 // Dictionary needed to grow.
8569 clear_storage();
8570 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008571 }
8572}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008573
8574 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008575 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8576 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008577 } else {
8578 index_offset_ += delta;
8579 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008580 }
8581
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008584 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008585 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008586 Handle<Map> map;
8587 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008588 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008591 }
8592 array->set_map(*map);
8593 array->set_length(*length);
8594 array->set_elements(*storage_);
8595 return array;
8596 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008597
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008598 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008599 // Convert storage to dictionary mode.
8600 void SetDictionaryMode(uint32_t index) {
8601 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008602 Handle<FixedArray> current_storage(*storage_);
8603 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008604 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008605 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8606 for (uint32_t i = 0; i < current_length; i++) {
8607 HandleScope loop_scope;
8608 Handle<Object> element(current_storage->get(i));
8609 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008610 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008612 if (!new_storage.is_identical_to(slow_storage)) {
8613 slow_storage = loop_scope.CloseAndEscape(new_storage);
8614 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008615 }
8616 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 clear_storage();
8618 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008619 fast_elements_ = false;
8620 }
8621
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008622 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 isolate_->global_handles()->Destroy(
8624 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008625 }
8626
8627 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 storage_ = Handle<FixedArray>::cast(
8629 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008630 }
8631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008632 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008633 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008634 // Index after last seen index. Always less than or equal to
8635 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008636 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008637 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008638};
8639
8640
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008641static uint32_t EstimateElementCount(Handle<JSArray> array) {
8642 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8643 int element_count = 0;
8644 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008645 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 // Fast elements can't have lengths that are not representable by
8647 // a 32-bit signed integer.
8648 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8649 int fast_length = static_cast<int>(length);
8650 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8651 for (int i = 0; i < fast_length; i++) {
8652 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008653 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008654 break;
8655 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008656 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008657 Handle<NumberDictionary> dictionary(
8658 NumberDictionary::cast(array->elements()));
8659 int capacity = dictionary->Capacity();
8660 for (int i = 0; i < capacity; i++) {
8661 Handle<Object> key(dictionary->KeyAt(i));
8662 if (dictionary->IsKey(*key)) {
8663 element_count++;
8664 }
8665 }
8666 break;
8667 }
8668 default:
8669 // External arrays are always dense.
8670 return length;
8671 }
8672 // As an estimate, we assume that the prototype doesn't contain any
8673 // inherited elements.
8674 return element_count;
8675}
8676
8677
8678
8679template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680static void IterateExternalArrayElements(Isolate* isolate,
8681 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008682 bool elements_are_ints,
8683 bool elements_are_guaranteed_smis,
8684 ArrayConcatVisitor* visitor) {
8685 Handle<ExternalArrayClass> array(
8686 ExternalArrayClass::cast(receiver->elements()));
8687 uint32_t len = static_cast<uint32_t>(array->length());
8688
8689 ASSERT(visitor != NULL);
8690 if (elements_are_ints) {
8691 if (elements_are_guaranteed_smis) {
8692 for (uint32_t j = 0; j < len; j++) {
8693 HandleScope loop_scope;
8694 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8695 visitor->visit(j, e);
8696 }
8697 } else {
8698 for (uint32_t j = 0; j < len; j++) {
8699 HandleScope loop_scope;
8700 int64_t val = static_cast<int64_t>(array->get(j));
8701 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8702 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8703 visitor->visit(j, e);
8704 } else {
8705 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008707 visitor->visit(j, e);
8708 }
8709 }
8710 }
8711 } else {
8712 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 HandleScope loop_scope(isolate);
8714 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008715 visitor->visit(j, e);
8716 }
8717 }
8718}
8719
8720
8721// Used for sorting indices in a List<uint32_t>.
8722static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8723 uint32_t a = *ap;
8724 uint32_t b = *bp;
8725 return (a == b) ? 0 : (a < b) ? -1 : 1;
8726}
8727
8728
8729static void CollectElementIndices(Handle<JSObject> object,
8730 uint32_t range,
8731 List<uint32_t>* indices) {
8732 JSObject::ElementsKind kind = object->GetElementsKind();
8733 switch (kind) {
8734 case JSObject::FAST_ELEMENTS: {
8735 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8736 uint32_t length = static_cast<uint32_t>(elements->length());
8737 if (range < length) length = range;
8738 for (uint32_t i = 0; i < length; i++) {
8739 if (!elements->get(i)->IsTheHole()) {
8740 indices->Add(i);
8741 }
8742 }
8743 break;
8744 }
8745 case JSObject::DICTIONARY_ELEMENTS: {
8746 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008747 uint32_t capacity = dict->Capacity();
8748 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008750 Handle<Object> k(dict->KeyAt(j));
8751 if (dict->IsKey(*k)) {
8752 ASSERT(k->IsNumber());
8753 uint32_t index = static_cast<uint32_t>(k->Number());
8754 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008755 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008756 }
8757 }
8758 }
8759 break;
8760 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008761 default: {
8762 int dense_elements_length;
8763 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008764 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008765 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008766 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008767 break;
8768 }
8769 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8770 dense_elements_length =
8771 ExternalByteArray::cast(object->elements())->length();
8772 break;
8773 }
8774 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8775 dense_elements_length =
8776 ExternalUnsignedByteArray::cast(object->elements())->length();
8777 break;
8778 }
8779 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8780 dense_elements_length =
8781 ExternalShortArray::cast(object->elements())->length();
8782 break;
8783 }
8784 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8785 dense_elements_length =
8786 ExternalUnsignedShortArray::cast(object->elements())->length();
8787 break;
8788 }
8789 case JSObject::EXTERNAL_INT_ELEMENTS: {
8790 dense_elements_length =
8791 ExternalIntArray::cast(object->elements())->length();
8792 break;
8793 }
8794 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8795 dense_elements_length =
8796 ExternalUnsignedIntArray::cast(object->elements())->length();
8797 break;
8798 }
8799 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8800 dense_elements_length =
8801 ExternalFloatArray::cast(object->elements())->length();
8802 break;
8803 }
8804 default:
8805 UNREACHABLE();
8806 dense_elements_length = 0;
8807 break;
8808 }
8809 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8810 if (range <= length) {
8811 length = range;
8812 // We will add all indices, so we might as well clear it first
8813 // and avoid duplicates.
8814 indices->Clear();
8815 }
8816 for (uint32_t i = 0; i < length; i++) {
8817 indices->Add(i);
8818 }
8819 if (length == range) return; // All indices accounted for already.
8820 break;
8821 }
8822 }
8823
8824 Handle<Object> prototype(object->GetPrototype());
8825 if (prototype->IsJSObject()) {
8826 // The prototype will usually have no inherited element indices,
8827 // but we have to check.
8828 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8829 }
8830}
8831
8832
8833/**
8834 * A helper function that visits elements of a JSArray in numerical
8835 * order.
8836 *
8837 * The visitor argument called for each existing element in the array
8838 * with the element index and the element's value.
8839 * Afterwards it increments the base-index of the visitor by the array
8840 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008841 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008842 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008843static bool IterateElements(Isolate* isolate,
8844 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008845 ArrayConcatVisitor* visitor) {
8846 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8847 switch (receiver->GetElementsKind()) {
8848 case JSObject::FAST_ELEMENTS: {
8849 // Run through the elements FixedArray and use HasElement and GetElement
8850 // to check the prototype for missing elements.
8851 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8852 int fast_length = static_cast<int>(length);
8853 ASSERT(fast_length <= elements->length());
8854 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 HandleScope loop_scope(isolate);
8856 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008857 if (!element_value->IsTheHole()) {
8858 visitor->visit(j, element_value);
8859 } else if (receiver->HasElement(j)) {
8860 // Call GetElement on receiver, not its prototype, or getters won't
8861 // have the correct receiver.
8862 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008863 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008864 visitor->visit(j, element_value);
8865 }
8866 }
8867 break;
8868 }
8869 case JSObject::DICTIONARY_ELEMENTS: {
8870 Handle<NumberDictionary> dict(receiver->element_dictionary());
8871 List<uint32_t> indices(dict->Capacity() / 2);
8872 // Collect all indices in the object and the prototypes less
8873 // than length. This might introduce duplicates in the indices list.
8874 CollectElementIndices(receiver, length, &indices);
8875 indices.Sort(&compareUInt32);
8876 int j = 0;
8877 int n = indices.length();
8878 while (j < n) {
8879 HandleScope loop_scope;
8880 uint32_t index = indices[j];
8881 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008882 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008883 visitor->visit(index, element);
8884 // Skip to next different index (i.e., omit duplicates).
8885 do {
8886 j++;
8887 } while (j < n && indices[j] == index);
8888 }
8889 break;
8890 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008891 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8892 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8893 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008894 for (uint32_t j = 0; j < length; j++) {
8895 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8896 visitor->visit(j, e);
8897 }
8898 break;
8899 }
8900 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8901 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008903 break;
8904 }
8905 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8906 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008908 break;
8909 }
8910 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8911 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008913 break;
8914 }
8915 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8916 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008918 break;
8919 }
8920 case JSObject::EXTERNAL_INT_ELEMENTS: {
8921 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008923 break;
8924 }
8925 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8926 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008927 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008928 break;
8929 }
8930 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8931 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008932 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008933 break;
8934 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008935 default:
8936 UNREACHABLE();
8937 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008938 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008939 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008940 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008941}
8942
8943
8944/**
8945 * Array::concat implementation.
8946 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008947 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008948 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008949 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008950static MaybeObject* Runtime_ArrayConcat(RUNTIME_CALLING_CONVENTION) {
8951 RUNTIME_GET_ISOLATE;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008952 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008953 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008954
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008955 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8956 int argument_count = static_cast<int>(arguments->length()->Number());
8957 RUNTIME_ASSERT(arguments->HasFastElements());
8958 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008959
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008960 // Pass 1: estimate the length and number of elements of the result.
8961 // The actual length can be larger if any of the arguments have getters
8962 // that mutate other arguments (but will otherwise be precise).
8963 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008964
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008965 uint32_t estimate_result_length = 0;
8966 uint32_t estimate_nof_elements = 0;
8967 {
8968 for (int i = 0; i < argument_count; i++) {
8969 HandleScope loop_scope;
8970 Handle<Object> obj(elements->get(i));
8971 uint32_t length_estimate;
8972 uint32_t element_estimate;
8973 if (obj->IsJSArray()) {
8974 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8975 length_estimate =
8976 static_cast<uint32_t>(array->length()->Number());
8977 element_estimate =
8978 EstimateElementCount(array);
8979 } else {
8980 length_estimate = 1;
8981 element_estimate = 1;
8982 }
8983 // Avoid overflows by capping at kMaxElementCount.
8984 if (JSObject::kMaxElementCount - estimate_result_length <
8985 length_estimate) {
8986 estimate_result_length = JSObject::kMaxElementCount;
8987 } else {
8988 estimate_result_length += length_estimate;
8989 }
8990 if (JSObject::kMaxElementCount - estimate_nof_elements <
8991 element_estimate) {
8992 estimate_nof_elements = JSObject::kMaxElementCount;
8993 } else {
8994 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008995 }
8996 }
8997 }
8998
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008999 // If estimated number of elements is more than half of length, a
9000 // fixed array (fast case) is more time and space-efficient than a
9001 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009002 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009003
9004 Handle<FixedArray> storage;
9005 if (fast_case) {
9006 // The backing storage array must have non-existing elements to
9007 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 storage = isolate->factory()->NewFixedArrayWithHoles(
9009 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009010 } else {
9011 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9012 uint32_t at_least_space_for = estimate_nof_elements +
9013 (estimate_nof_elements >> 2);
9014 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009016 }
9017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009019
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 for (int i = 0; i < argument_count; i++) {
9021 Handle<Object> obj(elements->get(i));
9022 if (obj->IsJSArray()) {
9023 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009025 return Failure::Exception();
9026 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009027 } else {
9028 visitor.visit(0, obj);
9029 visitor.increase_index_offset(1);
9030 }
9031 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009032
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009033 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009034}
9035
9036
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037// This will not allocate (flatten the string), but it may run
9038// very slowly for very deeply nested ConsStrings. For debugging use only.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039static MaybeObject* Runtime_GlobalPrint(RUNTIME_CALLING_CONVENTION) {
9040 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041 NoHandleAllocation ha;
9042 ASSERT(args.length() == 1);
9043
9044 CONVERT_CHECKED(String, string, args[0]);
9045 StringInputBuffer buffer(string);
9046 while (buffer.has_more()) {
9047 uint16_t character = buffer.GetNext();
9048 PrintF("%c", character);
9049 }
9050 return string;
9051}
9052
ager@chromium.org5ec48922009-05-05 07:25:34 +00009053// Moves all own elements of an object, that are below a limit, to positions
9054// starting at zero. All undefined values are placed after non-undefined values,
9055// and are followed by non-existing element. Does not change the length
9056// property.
9057// Returns the number of non-undefined elements collected.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058static MaybeObject* Runtime_RemoveArrayHoles(RUNTIME_CALLING_CONVENTION) {
9059 RUNTIME_GET_ISOLATE;
ager@chromium.org5ec48922009-05-05 07:25:34 +00009060 ASSERT(args.length() == 2);
9061 CONVERT_CHECKED(JSObject, object, args[0]);
9062 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9063 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064}
9065
9066
9067// Move contents of argument 0 (an array) to argument 1 (an array)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068static MaybeObject* Runtime_MoveArrayContents(RUNTIME_CALLING_CONVENTION) {
9069 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 ASSERT(args.length() == 2);
9071 CONVERT_CHECKED(JSArray, from, args[0]);
9072 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009073 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009074 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009075 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9076 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009077 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009078 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009079 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009080 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009081 Object* new_map;
9082 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009083 to->set_map(Map::cast(new_map));
9084 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009086 Object* obj;
9087 { MaybeObject* maybe_obj = from->ResetElements();
9088 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9089 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009090 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091 return to;
9092}
9093
9094
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009095// How many elements does this object/array have?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096static MaybeObject* Runtime_EstimateNumberOfElements(
9097 RUNTIME_CALLING_CONVENTION) {
9098 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009099 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009100 CONVERT_CHECKED(JSObject, object, args[0]);
9101 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009103 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009104 } else if (object->IsJSArray()) {
9105 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009107 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108 }
9109}
9110
9111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112static MaybeObject* Runtime_SwapElements(RUNTIME_CALLING_CONVENTION) {
9113 RUNTIME_GET_ISOLATE;
9114 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009115
9116 ASSERT_EQ(3, args.length());
9117
ager@chromium.orgac091b72010-05-05 07:34:42 +00009118 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009119 Handle<Object> key1 = args.at<Object>(1);
9120 Handle<Object> key2 = args.at<Object>(2);
9121
9122 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009123 if (!key1->ToArrayIndex(&index1)
9124 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009126 }
9127
ager@chromium.orgac091b72010-05-05 07:34:42 +00009128 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9129 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009130 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009131 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 RETURN_IF_EMPTY_HANDLE(isolate,
9135 SetElement(jsobject, index1, tmp2, kStrictMode));
9136 RETURN_IF_EMPTY_HANDLE(isolate,
9137 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009140}
9141
9142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009144// might have elements. Can either return keys (positive integers) or
9145// intervals (pair of a negative integer (-start-1) followed by a
9146// positive (length)) or undefined values.
9147// Intervals can span over some keys that are not in the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148static MaybeObject* Runtime_GetArrayKeys(RUNTIME_CALLING_CONVENTION) {
9149 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009152 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009154 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 // Create an array and get all the keys into it, then remove all the
9156 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009157 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 int keys_length = keys->length();
9159 for (int i = 0; i < keys_length; i++) {
9160 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009161 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009162 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 // Zap invalid keys.
9164 keys->set_undefined(i);
9165 }
9166 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009167 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009169 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009172 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009173 uint32_t actual_length =
9174 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009175 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 }
9181}
9182
9183
9184// DefineAccessor takes an optional final argument which is the
9185// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9186// to the way accessors are implemented, it is set for both the getter
9187// and setter on the first call to DefineAccessor and ignored on
9188// subsequent calls.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189static MaybeObject* Runtime_DefineAccessor(RUNTIME_CALLING_CONVENTION) {
9190 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9192 // Compute attributes.
9193 PropertyAttributes attributes = NONE;
9194 if (args.length() == 5) {
9195 CONVERT_CHECKED(Smi, attrs, args[4]);
9196 int value = attrs->value();
9197 // Only attribute bits should be set.
9198 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9199 attributes = static_cast<PropertyAttributes>(value);
9200 }
9201
9202 CONVERT_CHECKED(JSObject, obj, args[0]);
9203 CONVERT_CHECKED(String, name, args[1]);
9204 CONVERT_CHECKED(Smi, flag, args[2]);
9205 CONVERT_CHECKED(JSFunction, fun, args[3]);
9206 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9207}
9208
9209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210static MaybeObject* Runtime_LookupAccessor(RUNTIME_CALLING_CONVENTION) {
9211 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 ASSERT(args.length() == 3);
9213 CONVERT_CHECKED(JSObject, obj, args[0]);
9214 CONVERT_CHECKED(String, name, args[1]);
9215 CONVERT_CHECKED(Smi, flag, args[2]);
9216 return obj->LookupAccessor(name, flag->value() == 0);
9217}
9218
9219
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009220#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009221static MaybeObject* Runtime_DebugBreak(RUNTIME_CALLING_CONVENTION) {
9222 RUNTIME_GET_ISOLATE;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009223 ASSERT(args.length() == 0);
9224 return Execution::DebugBreakHelper();
9225}
9226
9227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228// Helper functions for wrapping and unwrapping stack frame ids.
9229static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009230 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 return Smi::FromInt(id >> 2);
9232}
9233
9234
9235static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9236 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9237}
9238
9239
9240// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009241// args[0]: debug event listener function to set or null or undefined for
9242// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243// args[1]: object supplied during callback
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244static MaybeObject* Runtime_SetDebugEventListener(RUNTIME_CALLING_CONVENTION) {
9245 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009247 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9248 args[0]->IsUndefined() ||
9249 args[0]->IsNull());
9250 Handle<Object> callback = args.at<Object>(0);
9251 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255}
9256
9257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258static MaybeObject* Runtime_Break(RUNTIME_CALLING_CONVENTION) {
9259 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +00009260 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 isolate->stack_guard()->DebugBreak();
9262 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263}
9264
9265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009266static MaybeObject* DebugLookupResultValue(Heap* heap,
9267 Object* receiver,
9268 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009269 LookupResult* result,
9270 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009271 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009273 case NORMAL:
9274 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009275 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 }
9278 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009279 case FIELD:
9280 value =
9281 JSObject::cast(
9282 result->holder())->FastPropertyAt(result->GetFieldIndex());
9283 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009284 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009285 }
9286 return value;
9287 case CONSTANT_FUNCTION:
9288 return result->GetConstantFunction();
9289 case CALLBACKS: {
9290 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009291 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009292 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009293 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009294 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009295 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009296 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 maybe_value = heap->isolate()->pending_exception();
9298 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009299 if (caught_exception != NULL) {
9300 *caught_exception = true;
9301 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009302 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009303 }
9304 return value;
9305 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009306 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009307 }
9308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009310 case MAP_TRANSITION:
9311 case CONSTANT_TRANSITION:
9312 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314 default:
9315 UNREACHABLE();
9316 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009317 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319}
9320
9321
ager@chromium.org32912102009-01-16 10:38:43 +00009322// Get debugger related details for an object property.
9323// args[0]: object holding property
9324// args[1]: name of the property
9325//
9326// The array returned contains the following information:
9327// 0: Property value
9328// 1: Property details
9329// 2: Property value is exception
9330// 3: Getter function if defined
9331// 4: Setter function if defined
9332// Items 2-4 are only filled if the property has either a getter or a setter
9333// defined through __defineGetter__ and/or __defineSetter__.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009334static MaybeObject* Runtime_DebugGetPropertyDetails(
9335 RUNTIME_CALLING_CONVENTION) {
9336 RUNTIME_GET_ISOLATE;
9337 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338
9339 ASSERT(args.length() == 2);
9340
9341 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9342 CONVERT_ARG_CHECKED(String, name, 1);
9343
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009344 // Make sure to set the current context to the context before the debugger was
9345 // entered (if the debugger is entered). The reason for switching context here
9346 // is that for some property lookups (accessors and interceptors) callbacks
9347 // into the embedding application can occour, and the embedding application
9348 // could have the assumption that its own global context is the current
9349 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009350 SaveContext save(isolate);
9351 if (isolate->debug()->InDebugger()) {
9352 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009353 }
9354
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009355 // Skip the global proxy as it has no properties and always delegates to the
9356 // real global object.
9357 if (obj->IsJSGlobalProxy()) {
9358 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9359 }
9360
9361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 // Check if the name is trivially convertible to an index and get the element
9363 // if so.
9364 uint32_t index;
9365 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009367 Object* element_or_char;
9368 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009370 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9371 return maybe_element_or_char;
9372 }
9373 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009374 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377 }
9378
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009379 // Find the number of objects making up this.
9380 int length = LocalPrototypeChainLength(*obj);
9381
9382 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009383 Handle<JSObject> jsproto = obj;
9384 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009385 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009386 jsproto->LocalLookup(*name, &result);
9387 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009388 // LookupResult is not GC safe as it holds raw object pointers.
9389 // GC can happen later in this code so put the required fields into
9390 // local variables using handles when required for later use.
9391 PropertyType result_type = result.type();
9392 Handle<Object> result_callback_obj;
9393 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9395 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009396 }
9397 Smi* property_details = result.GetPropertyDetails().AsSmi();
9398 // DebugLookupResultValue can cause GC so details from LookupResult needs
9399 // to be copied to handles before this.
9400 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009401 Object* raw_value;
9402 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009403 DebugLookupResultValue(isolate->heap(), *obj, *name,
9404 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009405 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9406 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009407 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009408
9409 // If the callback object is a fixed array then it contains JavaScript
9410 // getter and/or setter.
9411 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9412 result_callback_obj->IsFixedArray();
9413 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009415 details->set(0, *value);
9416 details->set(1, property_details);
9417 if (hasJavaScriptAccessors) {
9418 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419 caught_exception ? isolate->heap()->true_value()
9420 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009421 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9422 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9423 }
9424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009425 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009426 }
9427 if (i < length - 1) {
9428 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9429 }
9430 }
9431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009432 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433}
9434
9435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436static MaybeObject* Runtime_DebugGetProperty(RUNTIME_CALLING_CONVENTION) {
9437 RUNTIME_GET_ISOLATE;
9438 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439
9440 ASSERT(args.length() == 2);
9441
9442 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9443 CONVERT_ARG_CHECKED(String, name, 1);
9444
9445 LookupResult result;
9446 obj->Lookup(*name, &result);
9447 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009448 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451}
9452
9453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454// Return the property type calculated from the property details.
9455// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456static MaybeObject* Runtime_DebugPropertyTypeFromDetails(
9457 RUNTIME_CALLING_CONVENTION) {
9458 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459 ASSERT(args.length() == 1);
9460 CONVERT_CHECKED(Smi, details, args[0]);
9461 PropertyType type = PropertyDetails(details).type();
9462 return Smi::FromInt(static_cast<int>(type));
9463}
9464
9465
9466// Return the property attribute calculated from the property details.
9467// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(
9469 RUNTIME_CALLING_CONVENTION) {
9470 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009471 ASSERT(args.length() == 1);
9472 CONVERT_CHECKED(Smi, details, args[0]);
9473 PropertyAttributes attributes = PropertyDetails(details).attributes();
9474 return Smi::FromInt(static_cast<int>(attributes));
9475}
9476
9477
9478// Return the property insertion index calculated from the property details.
9479// args[0]: smi with property details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480static MaybeObject* Runtime_DebugPropertyIndexFromDetails(
9481 RUNTIME_CALLING_CONVENTION) {
9482 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483 ASSERT(args.length() == 1);
9484 CONVERT_CHECKED(Smi, details, args[0]);
9485 int index = PropertyDetails(details).index();
9486 return Smi::FromInt(index);
9487}
9488
9489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009490// Return property value from named interceptor.
9491// args[0]: object
9492// args[1]: property name
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(
9494 RUNTIME_CALLING_CONVENTION) {
9495 RUNTIME_GET_ISOLATE;
9496 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 ASSERT(args.length() == 2);
9498 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9499 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9500 CONVERT_ARG_CHECKED(String, name, 1);
9501
9502 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009503 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009504}
9505
9506
9507// Return element value from indexed interceptor.
9508// args[0]: object
9509// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009510static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 RUNTIME_CALLING_CONVENTION) {
9512 RUNTIME_GET_ISOLATE;
9513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 ASSERT(args.length() == 2);
9515 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9516 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9517 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9518
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009519 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520}
9521
9522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523static MaybeObject* Runtime_CheckExecutionState(RUNTIME_CALLING_CONVENTION) {
9524 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 ASSERT(args.length() >= 1);
9526 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009527 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528 if (isolate->debug()->break_id() == 0 ||
9529 break_id != isolate->debug()->break_id()) {
9530 return isolate->Throw(
9531 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532 }
9533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535}
9536
9537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538static MaybeObject* Runtime_GetFrameCount(RUNTIME_CALLING_CONVENTION) {
9539 RUNTIME_GET_ISOLATE;
9540 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541 ASSERT(args.length() == 1);
9542
9543 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009544 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009545 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009546 if (!maybe_result->ToObject(&result)) return maybe_result;
9547 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548
9549 // Count all frames which are relevant to debugging stack trace.
9550 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009551 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009552 if (id == StackFrame::NO_ID) {
9553 // If there is no JavaScript stack frame count is 0.
9554 return Smi::FromInt(0);
9555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009556 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9557 return Smi::FromInt(n);
9558}
9559
9560
9561static const int kFrameDetailsFrameIdIndex = 0;
9562static const int kFrameDetailsReceiverIndex = 1;
9563static const int kFrameDetailsFunctionIndex = 2;
9564static const int kFrameDetailsArgumentCountIndex = 3;
9565static const int kFrameDetailsLocalCountIndex = 4;
9566static const int kFrameDetailsSourcePositionIndex = 5;
9567static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009568static const int kFrameDetailsAtReturnIndex = 7;
9569static const int kFrameDetailsDebuggerFrameIndex = 8;
9570static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571
9572// Return an array with frame details
9573// args[0]: number: break id
9574// args[1]: number: frame index
9575//
9576// The array returned contains the following information:
9577// 0: Frame id
9578// 1: Receiver
9579// 2: Function
9580// 3: Argument count
9581// 4: Local count
9582// 5: Source position
9583// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009584// 7: Is at return
9585// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586// Arguments name, value
9587// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009588// Return value if any
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
9590 RUNTIME_GET_ISOLATE;
9591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 ASSERT(args.length() == 2);
9593
9594 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009595 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 if (!maybe_check->ToObject(&check)) return maybe_check;
9598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009599 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009600 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601
9602 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009603 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009604 if (id == StackFrame::NO_ID) {
9605 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009607 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009608 int count = 0;
9609 JavaScriptFrameIterator it(id);
9610 for (; !it.done(); it.Advance()) {
9611 if (count == index) break;
9612 count++;
9613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009614 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009616 bool is_optimized_frame =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009617 it.frame()->LookupCode(isolate)->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009619 // Traverse the saved contexts chain to find the active context for the
9620 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009622 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009623 save = save->prev();
9624 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009625 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626
9627 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629
9630 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009631 int position =
9632 it.frame()->LookupCode(isolate)->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009633
9634 // Check for constructor frame.
9635 bool constructor = it.frame()->IsConstructor();
9636
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009637 // Get scope info and read from it for local variable information.
9638 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009639 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009640 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641
9642 // Get the context.
9643 Handle<Context> context(Context::cast(it.frame()->context()));
9644
9645 // Get the locals names and values into a temporary array.
9646 //
9647 // TODO(1240907): Hide compiler-introduced stack variables
9648 // (e.g. .result)? For users of the debugger, they will probably be
9649 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009650 Handle<FixedArray> locals =
9651 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009653 // Fill in the names of the locals.
9654 for (int i = 0; i < info.NumberOfLocals(); i++) {
9655 locals->set(i * 2, *info.LocalName(i));
9656 }
9657
9658 // Fill in the values of the locals.
9659 for (int i = 0; i < info.NumberOfLocals(); i++) {
9660 if (is_optimized_frame) {
9661 // If we are inspecting an optimized frame use undefined as the
9662 // value for all locals.
9663 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009664 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009665 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009667 } else if (i < info.number_of_stack_slots()) {
9668 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9670 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 // Traverse the context chain to the function context as all local
9672 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009673 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009674 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 context = Handle<Context>(context->previous());
9676 }
9677 ASSERT(context->is_function_context());
9678 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009679 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009680 }
9681 }
9682
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009683 // Check whether this frame is positioned at return. If not top
9684 // frame or if the frame is optimized it cannot be at a return.
9685 bool at_return = false;
9686 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009687 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009688 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009689
9690 // If positioned just before return find the value to be returned and add it
9691 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009693 if (at_return) {
9694 StackFrameIterator it2;
9695 Address internal_frame_sp = NULL;
9696 while (!it2.done()) {
9697 if (it2.frame()->is_internal()) {
9698 internal_frame_sp = it2.frame()->sp();
9699 } else {
9700 if (it2.frame()->is_java_script()) {
9701 if (it2.frame()->id() == it.frame()->id()) {
9702 // The internal frame just before the JavaScript frame contains the
9703 // value to return on top. A debug break at return will create an
9704 // internal frame to store the return value (eax/rax/r0) before
9705 // entering the debug break exit frame.
9706 if (internal_frame_sp != NULL) {
9707 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009708 Handle<Object>(Memory::Object_at(internal_frame_sp),
9709 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009710 break;
9711 }
9712 }
9713 }
9714
9715 // Indicate that the previous frame was not an internal frame.
9716 internal_frame_sp = NULL;
9717 }
9718 it2.Advance();
9719 }
9720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721
9722 // Now advance to the arguments adapter frame (if any). It contains all
9723 // the provided parameters whereas the function frame always have the number
9724 // of arguments matching the functions parameters. The rest of the
9725 // information (except for what is collected above) is the same.
9726 it.AdvanceToArgumentsFrame();
9727
9728 // Find the number of arguments to fill. At least fill the number of
9729 // parameters for the function and fill more if more parameters are provided.
9730 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009731 if (argument_count < it.frame()->ComputeParametersCount()) {
9732 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 }
9734
9735 // Calculate the size of the result.
9736 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009737 2 * (argument_count + info.NumberOfLocals()) +
9738 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740
9741 // Add the frame id.
9742 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9743
9744 // Add the function (same as in function frame).
9745 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9746
9747 // Add the arguments count.
9748 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9749
9750 // Add the locals count
9751 details->set(kFrameDetailsLocalCountIndex,
9752 Smi::FromInt(info.NumberOfLocals()));
9753
9754 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009755 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009756 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9757 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 }
9760
9761 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009762 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009763
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009764 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009767 // Add information on whether this frame is invoked in the debugger context.
9768 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009769 heap->ToBoolean(*save->context() ==
9770 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771
9772 // Fill the dynamic part.
9773 int details_index = kFrameDetailsFirstDynamicIndex;
9774
9775 // Add arguments name and value.
9776 for (int i = 0; i < argument_count; i++) {
9777 // Name of the argument.
9778 if (i < info.number_of_parameters()) {
9779 details->set(details_index++, *info.parameter_name(i));
9780 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 }
9783
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009784 // Parameter value. If we are inspecting an optimized frame, use
9785 // undefined as the value.
9786 //
9787 // TODO(3141533): We should be able to get the actual parameter
9788 // value for optimized frames.
9789 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009790 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009791 details->set(details_index++, it.frame()->GetParameter(i));
9792 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794 }
9795 }
9796
9797 // Add locals name and value from the temporary copy from the function frame.
9798 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9799 details->set(details_index++, locals->get(i));
9800 }
9801
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009802 // Add the value being returned.
9803 if (at_return) {
9804 details->set(details_index++, *return_value);
9805 }
9806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807 // Add the receiver (same as in function frame).
9808 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9809 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009810 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009811 if (!receiver->IsJSObject()) {
9812 // If the receiver is NOT a JSObject we have hit an optimization
9813 // where a value object is not converted into a wrapped JS objects.
9814 // To hide this optimization from the debugger, we wrap the receiver
9815 // by creating correct wrapper object based on the calling frame's
9816 // global context.
9817 it.Advance();
9818 Handle<Context> calling_frames_global_context(
9819 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 receiver =
9821 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 }
9823 details->set(kFrameDetailsReceiverIndex, *receiver);
9824
9825 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009827}
9828
9829
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009830// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009831static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009832 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009833 Handle<SerializedScopeInfo> serialized_scope_info,
9834 ScopeInfo<>& scope_info,
9835 Handle<Context> context,
9836 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009837 // Fill all context locals to the context extension.
9838 for (int i = Context::MIN_CONTEXT_SLOTS;
9839 i < scope_info.number_of_context_slots();
9840 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009841 int context_index = serialized_scope_info->ContextSlotIndex(
9842 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009843
9844 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845 if (*scope_info.context_slot_name(i) !=
9846 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009847 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009848 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009849 SetProperty(scope_object,
9850 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009852 NONE,
9853 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009854 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009855 }
9856 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009857
9858 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009859}
9860
9861
9862// Create a plain JSObject which materializes the local scope for the specified
9863// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009864static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9865 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009866 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009867 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009868 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9869 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009870
9871 // Allocate and initialize a JSObject with all the arguments, stack locals
9872 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009873 Handle<JSObject> local_scope =
9874 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009875
9876 // First fill all parameters.
9877 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009878 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009879 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009880 SetProperty(local_scope,
9881 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009883 NONE,
9884 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009885 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009886 }
9887
9888 // Second fill all stack locals.
9889 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009890 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009891 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009892 SetProperty(local_scope,
9893 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009894 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009895 NONE,
9896 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009897 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009898 }
9899
9900 // Third fill all context locals.
9901 Handle<Context> frame_context(Context::cast(frame->context()));
9902 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 if (!CopyContextLocalsToScopeObject(isolate,
9904 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009905 function_context, local_scope)) {
9906 return Handle<JSObject>();
9907 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009908
9909 // Finally copy any properties from the function context extension. This will
9910 // be variables introduced by eval.
9911 if (function_context->closure() == *function) {
9912 if (function_context->has_extension() &&
9913 !function_context->IsGlobalContext()) {
9914 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009915 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009916 for (int i = 0; i < keys->length(); i++) {
9917 // Names of variables introduced by eval are strings.
9918 ASSERT(keys->get(i)->IsString());
9919 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009920 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009921 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009922 SetProperty(local_scope,
9923 key,
9924 GetProperty(ext, key),
9925 NONE,
9926 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009927 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009928 }
9929 }
9930 }
9931 return local_scope;
9932}
9933
9934
9935// Create a plain JSObject which materializes the closure content for the
9936// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9938 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009939 ASSERT(context->is_function_context());
9940
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009941 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009942 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9943 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009944
9945 // Allocate and initialize a JSObject with all the content of theis function
9946 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 Handle<JSObject> closure_scope =
9948 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009949
9950 // Check whether the arguments shadow object exists.
9951 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 shared->scope_info()->ContextSlotIndex(
9953 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009954 if (arguments_shadow_index >= 0) {
9955 // In this case all the arguments are available in the arguments shadow
9956 // object.
9957 Handle<JSObject> arguments_shadow(
9958 JSObject::cast(context->get(arguments_shadow_index)));
9959 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009960 // We don't expect exception-throwing getters on the arguments shadow.
9961 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009962 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009963 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009964 SetProperty(closure_scope,
9965 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009966 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009967 NONE,
9968 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009969 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009970 }
9971 }
9972
9973 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009974 if (!CopyContextLocalsToScopeObject(isolate,
9975 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009976 context, closure_scope)) {
9977 return Handle<JSObject>();
9978 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009979
9980 // Finally copy any properties from the function context extension. This will
9981 // be variables introduced by eval.
9982 if (context->has_extension()) {
9983 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009984 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009985 for (int i = 0; i < keys->length(); i++) {
9986 // Names of variables introduced by eval are strings.
9987 ASSERT(keys->get(i)->IsString());
9988 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009989 RETURN_IF_EMPTY_HANDLE_VALUE(
9990 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009991 SetProperty(closure_scope,
9992 key,
9993 GetProperty(ext, key),
9994 NONE,
9995 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009996 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009997 }
9998 }
9999
10000 return closure_scope;
10001}
10002
10003
10004// Iterate over the actual scopes visible from a stack frame. All scopes are
10005// backed by an actual context except the local scope, which is inserted
10006// "artifically" in the context chain.
10007class ScopeIterator {
10008 public:
10009 enum ScopeType {
10010 ScopeTypeGlobal = 0,
10011 ScopeTypeLocal,
10012 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010013 ScopeTypeClosure,
10014 // Every catch block contains an implicit with block (its parameter is
10015 // a JSContextExtensionObject) that extends current scope with a variable
10016 // holding exception object. Such with blocks are treated as scopes of their
10017 // own type.
10018 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010019 };
10020
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10022 : isolate_(isolate),
10023 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010024 function_(JSFunction::cast(frame->function())),
10025 context_(Context::cast(frame->context())),
10026 local_done_(false),
10027 at_local_(false) {
10028
10029 // Check whether the first scope is actually a local scope.
10030 if (context_->IsGlobalContext()) {
10031 // If there is a stack slot for .result then this local scope has been
10032 // created for evaluating top level code and it is not a real local scope.
10033 // Checking for the existence of .result seems fragile, but the scope info
10034 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010035 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010037 at_local_ = index < 0;
10038 } else if (context_->is_function_context()) {
10039 at_local_ = true;
10040 }
10041 }
10042
10043 // More scopes?
10044 bool Done() { return context_.is_null(); }
10045
10046 // Move to the next scope.
10047 void Next() {
10048 // If at a local scope mark the local scope as passed.
10049 if (at_local_) {
10050 at_local_ = false;
10051 local_done_ = true;
10052
10053 // If the current context is not associated with the local scope the
10054 // current context is the next real scope, so don't move to the next
10055 // context in this case.
10056 if (context_->closure() != *function_) {
10057 return;
10058 }
10059 }
10060
10061 // The global scope is always the last in the chain.
10062 if (context_->IsGlobalContext()) {
10063 context_ = Handle<Context>();
10064 return;
10065 }
10066
10067 // Move to the next context.
10068 if (context_->is_function_context()) {
10069 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10070 } else {
10071 context_ = Handle<Context>(context_->previous());
10072 }
10073
10074 // If passing the local scope indicate that the current scope is now the
10075 // local scope.
10076 if (!local_done_ &&
10077 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10078 at_local_ = true;
10079 }
10080 }
10081
10082 // Return the type of the current scope.
10083 int Type() {
10084 if (at_local_) {
10085 return ScopeTypeLocal;
10086 }
10087 if (context_->IsGlobalContext()) {
10088 ASSERT(context_->global()->IsGlobalObject());
10089 return ScopeTypeGlobal;
10090 }
10091 if (context_->is_function_context()) {
10092 return ScopeTypeClosure;
10093 }
10094 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010095 // Current scope is either an explicit with statement or a with statement
10096 // implicitely generated for a catch block.
10097 // If the extension object here is a JSContextExtensionObject then
10098 // current with statement is one frome a catch block otherwise it's a
10099 // regular with statement.
10100 if (context_->extension()->IsJSContextExtensionObject()) {
10101 return ScopeTypeCatch;
10102 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010103 return ScopeTypeWith;
10104 }
10105
10106 // Return the JavaScript object with the content of the current scope.
10107 Handle<JSObject> ScopeObject() {
10108 switch (Type()) {
10109 case ScopeIterator::ScopeTypeGlobal:
10110 return Handle<JSObject>(CurrentContext()->global());
10111 break;
10112 case ScopeIterator::ScopeTypeLocal:
10113 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010115 break;
10116 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010117 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010118 // Return the with object.
10119 return Handle<JSObject>(CurrentContext()->extension());
10120 break;
10121 case ScopeIterator::ScopeTypeClosure:
10122 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010123 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010124 break;
10125 }
10126 UNREACHABLE();
10127 return Handle<JSObject>();
10128 }
10129
10130 // Return the context for this scope. For the local context there might not
10131 // be an actual context.
10132 Handle<Context> CurrentContext() {
10133 if (at_local_ && context_->closure() != *function_) {
10134 return Handle<Context>();
10135 }
10136 return context_;
10137 }
10138
10139#ifdef DEBUG
10140 // Debug print of the content of the current scope.
10141 void DebugPrint() {
10142 switch (Type()) {
10143 case ScopeIterator::ScopeTypeGlobal:
10144 PrintF("Global:\n");
10145 CurrentContext()->Print();
10146 break;
10147
10148 case ScopeIterator::ScopeTypeLocal: {
10149 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010150 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010151 scope_info.Print();
10152 if (!CurrentContext().is_null()) {
10153 CurrentContext()->Print();
10154 if (CurrentContext()->has_extension()) {
10155 Handle<JSObject> extension =
10156 Handle<JSObject>(CurrentContext()->extension());
10157 if (extension->IsJSContextExtensionObject()) {
10158 extension->Print();
10159 }
10160 }
10161 }
10162 break;
10163 }
10164
10165 case ScopeIterator::ScopeTypeWith: {
10166 PrintF("With:\n");
10167 Handle<JSObject> extension =
10168 Handle<JSObject>(CurrentContext()->extension());
10169 extension->Print();
10170 break;
10171 }
10172
ager@chromium.orga1645e22009-09-09 19:27:10 +000010173 case ScopeIterator::ScopeTypeCatch: {
10174 PrintF("Catch:\n");
10175 Handle<JSObject> extension =
10176 Handle<JSObject>(CurrentContext()->extension());
10177 extension->Print();
10178 break;
10179 }
10180
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010181 case ScopeIterator::ScopeTypeClosure: {
10182 PrintF("Closure:\n");
10183 CurrentContext()->Print();
10184 if (CurrentContext()->has_extension()) {
10185 Handle<JSObject> extension =
10186 Handle<JSObject>(CurrentContext()->extension());
10187 if (extension->IsJSContextExtensionObject()) {
10188 extension->Print();
10189 }
10190 }
10191 break;
10192 }
10193
10194 default:
10195 UNREACHABLE();
10196 }
10197 PrintF("\n");
10198 }
10199#endif
10200
10201 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010203 JavaScriptFrame* frame_;
10204 Handle<JSFunction> function_;
10205 Handle<Context> context_;
10206 bool local_done_;
10207 bool at_local_;
10208
10209 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10210};
10211
10212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213static MaybeObject* Runtime_GetScopeCount(RUNTIME_CALLING_CONVENTION) {
10214 RUNTIME_GET_ISOLATE;
10215 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010216 ASSERT(args.length() == 2);
10217
10218 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010219 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010221 if (!maybe_check->ToObject(&check)) return maybe_check;
10222 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010223 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10224
10225 // Get the frame where the debugging is performed.
10226 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10227 JavaScriptFrameIterator it(id);
10228 JavaScriptFrame* frame = it.frame();
10229
10230 // Count the visible scopes.
10231 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010233 n++;
10234 }
10235
10236 return Smi::FromInt(n);
10237}
10238
10239
10240static const int kScopeDetailsTypeIndex = 0;
10241static const int kScopeDetailsObjectIndex = 1;
10242static const int kScopeDetailsSize = 2;
10243
10244// Return an array with scope details
10245// args[0]: number: break id
10246// args[1]: number: frame index
10247// args[2]: number: scope index
10248//
10249// The array returned contains the following information:
10250// 0: Scope type
10251// 1: Scope object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252static MaybeObject* Runtime_GetScopeDetails(RUNTIME_CALLING_CONVENTION) {
10253 RUNTIME_GET_ISOLATE;
10254 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010255 ASSERT(args.length() == 3);
10256
10257 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010258 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010260 if (!maybe_check->ToObject(&check)) return maybe_check;
10261 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010262 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10263 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10264
10265 // Get the frame where the debugging is performed.
10266 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10267 JavaScriptFrameIterator frame_it(id);
10268 JavaScriptFrame* frame = frame_it.frame();
10269
10270 // Find the requested scope.
10271 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010272 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010273 for (; !it.Done() && n < index; it.Next()) {
10274 n++;
10275 }
10276 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010278 }
10279
10280 // Calculate the size of the result.
10281 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010283
10284 // Fill in scope details.
10285 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010286 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010288 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010290 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010291}
10292
10293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010294static MaybeObject* Runtime_DebugPrintScopes(RUNTIME_CALLING_CONVENTION) {
10295 RUNTIME_GET_ISOLATE;
10296 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010297 ASSERT(args.length() == 0);
10298
10299#ifdef DEBUG
10300 // Print the scopes for the top frame.
10301 StackFrameLocator locator;
10302 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010304 it.DebugPrint();
10305 }
10306#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010307 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010308}
10309
10310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311static MaybeObject* Runtime_GetThreadCount(RUNTIME_CALLING_CONVENTION) {
10312 RUNTIME_GET_ISOLATE;
10313 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010314 ASSERT(args.length() == 1);
10315
10316 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010317 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010319 if (!maybe_result->ToObject(&result)) return maybe_result;
10320 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010321
10322 // Count all archived V8 threads.
10323 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 for (ThreadState* thread =
10325 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010326 thread != NULL;
10327 thread = thread->Next()) {
10328 n++;
10329 }
10330
10331 // Total number of threads is current thread and archived threads.
10332 return Smi::FromInt(n + 1);
10333}
10334
10335
10336static const int kThreadDetailsCurrentThreadIndex = 0;
10337static const int kThreadDetailsThreadIdIndex = 1;
10338static const int kThreadDetailsSize = 2;
10339
10340// Return an array with thread details
10341// args[0]: number: break id
10342// args[1]: number: thread index
10343//
10344// The array returned contains the following information:
10345// 0: Is current thread?
10346// 1: Thread id
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347static MaybeObject* Runtime_GetThreadDetails(RUNTIME_CALLING_CONVENTION) {
10348 RUNTIME_GET_ISOLATE;
10349 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010350 ASSERT(args.length() == 2);
10351
10352 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010353 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010355 if (!maybe_check->ToObject(&check)) return maybe_check;
10356 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010357 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10358
10359 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360 Handle<FixedArray> details =
10361 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010362
10363 // Thread index 0 is current thread.
10364 if (index == 0) {
10365 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 details->set(kThreadDetailsCurrentThreadIndex,
10367 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010368 details->set(kThreadDetailsThreadIdIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010369 Smi::FromInt(
10370 isolate->thread_manager()->CurrentId()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010371 } else {
10372 // Find the thread with the requested index.
10373 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 ThreadState* thread =
10375 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010376 while (index != n && thread != NULL) {
10377 thread = thread->Next();
10378 n++;
10379 }
10380 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010382 }
10383
10384 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 details->set(kThreadDetailsCurrentThreadIndex,
10386 isolate->heap()->false_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010387 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
10388 }
10389
10390 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010392}
10393
10394
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010395// Sets the disable break state
10396// args[0]: disable break state
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397static MaybeObject* Runtime_SetDisableBreak(RUNTIME_CALLING_CONVENTION) {
10398 RUNTIME_GET_ISOLATE;
10399 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010400 ASSERT(args.length() == 1);
10401 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010402 isolate->debug()->set_disable_break(disable_break);
10403 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010404}
10405
10406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010407static MaybeObject* Runtime_GetBreakLocations(RUNTIME_CALLING_CONVENTION) {
10408 RUNTIME_GET_ISOLATE;
10409 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410 ASSERT(args.length() == 1);
10411
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010412 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10413 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 // Find the number of break points
10415 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010416 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 Handle<FixedArray>::cast(break_locations));
10420}
10421
10422
10423// Set a break point in a function
10424// args[0]: function
10425// args[1]: number: break source position (within the function source)
10426// args[2]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427static MaybeObject* Runtime_SetFunctionBreakPoint(RUNTIME_CALLING_CONVENTION) {
10428 RUNTIME_GET_ISOLATE;
10429 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010431 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10432 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10434 RUNTIME_ASSERT(source_position >= 0);
10435 Handle<Object> break_point_object_arg = args.at<Object>(2);
10436
10437 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10439 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010440
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010441 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442}
10443
10444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10446 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010447 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448 // Iterate the heap looking for SharedFunctionInfo generated from the
10449 // script. The inner most SharedFunctionInfo containing the source position
10450 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010451 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452 // which is found is not compiled it is compiled and the heap is iterated
10453 // again as the compilation might create inner functions from the newly
10454 // compiled function and the actual requested break point might be in one of
10455 // these functions.
10456 bool done = false;
10457 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010458 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 while (!done) {
10461 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010462 for (HeapObject* obj = iterator.next();
10463 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 if (obj->IsSharedFunctionInfo()) {
10465 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10466 if (shared->script() == *script) {
10467 // If the SharedFunctionInfo found has the requested script data and
10468 // contains the source position it is a candidate.
10469 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010470 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 start_position = shared->start_position();
10472 }
10473 if (start_position <= position &&
10474 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010475 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 // candidate this is the new candidate.
10477 if (target.is_null()) {
10478 target_start_position = start_position;
10479 target = shared;
10480 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010481 if (target_start_position == start_position &&
10482 shared->end_position() == target->end_position()) {
10483 // If a top-level function contain only one function
10484 // declartion the source for the top-level and the function is
10485 // the same. In that case prefer the non top-level function.
10486 if (!shared->is_toplevel()) {
10487 target_start_position = start_position;
10488 target = shared;
10489 }
10490 } else if (target_start_position <= start_position &&
10491 shared->end_position() <= target->end_position()) {
10492 // This containment check includes equality as a function inside
10493 // a top-level function can share either start or end position
10494 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 target_start_position = start_position;
10496 target = shared;
10497 }
10498 }
10499 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500 }
10501 }
10502 }
10503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010505 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506 }
10507
10508 // If the candidate found is compiled we are done. NOTE: when lazy
10509 // compilation of inner functions is introduced some additional checking
10510 // needs to be done here to compile inner functions.
10511 done = target->is_compiled();
10512 if (!done) {
10513 // If the candidate is not compiled compile it to reveal any inner
10514 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010515 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 }
10517 }
10518
10519 return *target;
10520}
10521
10522
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010523// Changes the state of a break point in a script and returns source position
10524// where break point was set. NOTE: Regarding performance see the NOTE for
10525// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526// args[0]: script to set break point in
10527// args[1]: number: break source position (within the script source)
10528// args[2]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529static MaybeObject* Runtime_SetScriptBreakPoint(RUNTIME_CALLING_CONVENTION) {
10530 RUNTIME_GET_ISOLATE;
10531 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 ASSERT(args.length() == 3);
10533 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10534 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10535 RUNTIME_ASSERT(source_position >= 0);
10536 Handle<Object> break_point_object_arg = args.at<Object>(2);
10537
10538 // Get the script from the script wrapper.
10539 RUNTIME_ASSERT(wrapper->value()->IsScript());
10540 Handle<Script> script(Script::cast(wrapper->value()));
10541
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010542 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010543 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544 if (!result->IsUndefined()) {
10545 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10546 // Find position within function. The script position might be before the
10547 // source position of the first function.
10548 int position;
10549 if (shared->start_position() > source_position) {
10550 position = 0;
10551 } else {
10552 position = source_position - shared->start_position();
10553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010554 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010555 position += shared->start_position();
10556 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559}
10560
10561
10562// Clear a break point
10563// args[0]: number: break point object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564static MaybeObject* Runtime_ClearBreakPoint(RUNTIME_CALLING_CONVENTION) {
10565 RUNTIME_GET_ISOLATE;
10566 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 ASSERT(args.length() == 1);
10568 Handle<Object> break_point_object_arg = args.at<Object>(0);
10569
10570 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010571 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574}
10575
10576
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010577// Change the state of break on exceptions.
10578// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10579// args[1]: Boolean indicating on/off.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580static MaybeObject* Runtime_ChangeBreakOnException(RUNTIME_CALLING_CONVENTION) {
10581 RUNTIME_GET_ISOLATE;
10582 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010584 RUNTIME_ASSERT(args[0]->IsNumber());
10585 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010587 // If the number doesn't match an enum value, the ChangeBreakOnException
10588 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 ExceptionBreakType type =
10590 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010591 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 isolate->debug()->ChangeBreakOnException(type, enable);
10593 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594}
10595
10596
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010597// Returns the state of break on exceptions
10598// args[0]: boolean indicating uncaught exceptions
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010599static MaybeObject* Runtime_IsBreakOnException(RUNTIME_CALLING_CONVENTION) {
10600 RUNTIME_GET_ISOLATE;
10601 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010602 ASSERT(args.length() == 1);
10603 RUNTIME_ASSERT(args[0]->IsNumber());
10604
10605 ExceptionBreakType type =
10606 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010608 return Smi::FromInt(result);
10609}
10610
10611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612// Prepare for stepping
10613// args[0]: break id for checking execution state
10614// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010615// args[2]: number of times to perform the step, for step out it is the number
10616// of frames to step down.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617static MaybeObject* Runtime_PrepareStep(RUNTIME_CALLING_CONVENTION) {
10618 RUNTIME_GET_ISOLATE;
10619 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620 ASSERT(args.length() == 3);
10621 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010622 Object* check;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010624 if (!maybe_check->ToObject(&check)) return maybe_check;
10625 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628 }
10629
10630 // Get the step action and check validity.
10631 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10632 if (step_action != StepIn &&
10633 step_action != StepNext &&
10634 step_action != StepOut &&
10635 step_action != StepInMin &&
10636 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638 }
10639
10640 // Get the number of steps.
10641 int step_count = NumberToInt32(args[2]);
10642 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010643 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 }
10645
ager@chromium.orga1645e22009-09-09 19:27:10 +000010646 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10651 step_count);
10652 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653}
10654
10655
10656// Clear all stepping set by PrepareStep.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657static MaybeObject* Runtime_ClearStepping(RUNTIME_CALLING_CONVENTION) {
10658 RUNTIME_GET_ISOLATE;
10659 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010660 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010661 isolate->debug()->ClearStepping();
10662 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663}
10664
10665
10666// Creates a copy of the with context chain. The copy of the context chain is
10667// is linked to the function context supplied.
10668static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10669 Handle<Context> function_context) {
10670 // At the bottom of the chain. Return the function context to link to.
10671 if (context_chain->is_function_context()) {
10672 return function_context;
10673 }
10674
10675 // Recursively copy the with contexts.
10676 Handle<Context> previous(context_chain->previous());
10677 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010678 Handle<Context> context = CopyWithContextChain(function_context, previous);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 return context->GetIsolate()->factory()->NewWithContext(
10680 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010681}
10682
10683
10684// Helper function to find or create the arguments object for
10685// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686static Handle<Object> GetArgumentsObject(Isolate* isolate,
10687 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010688 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010689 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690 const ScopeInfo<>* sinfo,
10691 Handle<Context> function_context) {
10692 // Try to find the value of 'arguments' to pass as parameter. If it is not
10693 // found (that is the debugged function does not reference 'arguments' and
10694 // does not support eval) then create an 'arguments' object.
10695 int index;
10696 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010699 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700 }
10701 }
10702
10703 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10705 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010707 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708 }
10709 }
10710
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010711 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 Handle<JSObject> arguments =
10713 isolate->factory()->NewArgumentsObject(function, length);
10714 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010715
10716 AssertNoAllocation no_gc;
10717 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010719 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010721 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722 return arguments;
10723}
10724
10725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010726static const char kSourceStr[] =
10727 "(function(arguments,__source__){return eval(__source__);})";
10728
10729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010731// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732// extension part has all the parameters and locals of the function on the
10733// stack frame. A function which calls eval with the code to evaluate is then
10734// compiled in this context and called in this context. As this context
10735// replaces the context of the function on the stack frame a new (empty)
10736// function is created as well to be used as the closure for the context.
10737// This function and the context acts as replacements for the function on the
10738// stack frame presenting the same view of the values of parameters and
10739// local variables as if the piece of JavaScript was evaluated at the point
10740// where the function on the stack frame is currently stopped.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010741static MaybeObject* Runtime_DebugEvaluate(RUNTIME_CALLING_CONVENTION) {
10742 RUNTIME_GET_ISOLATE;
10743 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744
10745 // Check the execution state and decode arguments frame and source to be
10746 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010747 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010748 Object* check_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10750 isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010751 if (!maybe_check_result->ToObject(&check_result)) {
10752 return maybe_check_result;
10753 }
10754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10756 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010757 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010758 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010759
10760 // Handle the processing of break.
10761 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
10763 // Get the frame where the debugging is performed.
10764 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10765 JavaScriptFrameIterator it(id);
10766 JavaScriptFrame* frame = it.frame();
10767 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010768 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010769 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770
10771 // Traverse the saved contexts chain to find the active context for the
10772 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010773 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010774 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 save = save->prev();
10776 }
10777 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 SaveContext savex(isolate);
10779 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780
10781 // Create the (empty) function replacing the function on the stack frame for
10782 // the purpose of evaluating in the context created below. It is important
10783 // that this function does not describe any parameters and local variables
10784 // in the context. If it does then this will cause problems with the lookup
10785 // in Context::Lookup, where context slots for parameters and local variables
10786 // are looked at before the extension object.
10787 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10789 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790 go_between->set_context(function->context());
10791#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010792 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010793 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10794 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10795#endif
10796
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010798 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10799 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800
10801 // Allocate a new context for the debug evaluation and set the extension
10802 // object build.
10803 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010804 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10805 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010806 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010808 Handle<Context> frame_context(Context::cast(frame->context()));
10809 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810 context = CopyWithContextChain(frame_context, context);
10811
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010812 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010814 Handle<JSObject>::cast(additional_context), false);
10815 }
10816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010817 // Wrap the evaluation statement in a new function compiled in the newly
10818 // created context. The function has one parameter which has to be called
10819 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010820 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010821 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010824 isolate->factory()->NewStringFromAscii(
10825 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010826
10827 // Currently, the eval code will be executed in non-strict mode,
10828 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010829 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010830 Compiler::CompileEval(function_source,
10831 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010832 context->IsGlobalContext(),
10833 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010834 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837
10838 // Invoke the result of the compilation to get the evaluation function.
10839 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010841 Handle<Object> evaluation_function =
10842 Execution::Call(compiled_function, receiver, 0, NULL,
10843 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010844 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10847 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010848 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849
10850 // Invoke the evaluation function and return the result.
10851 const int argc = 2;
10852 Object** argv[argc] = { arguments.location(),
10853 Handle<Object>::cast(source).location() };
10854 Handle<Object> result =
10855 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10856 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010857 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010858
10859 // Skip the global proxy as it has no properties and always delegates to the
10860 // real global object.
10861 if (result->IsJSGlobalProxy()) {
10862 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10863 }
10864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865 return *result;
10866}
10867
10868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010869static MaybeObject* Runtime_DebugEvaluateGlobal(RUNTIME_CALLING_CONVENTION) {
10870 RUNTIME_GET_ISOLATE;
10871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872
10873 // Check the execution state and decode arguments frame and source to be
10874 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010875 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010876 Object* check_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
10878 isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010879 if (!maybe_check_result->ToObject(&check_result)) {
10880 return maybe_check_result;
10881 }
10882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010883 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010884 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010885 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010886
10887 // Handle the processing of break.
10888 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889
10890 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010891 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010893 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894 top = top->prev();
10895 }
10896 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010897 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898 }
10899
10900 // Get the global context now set to the top context from before the
10901 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010902 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010904 bool is_global = true;
10905
10906 if (additional_context->IsJSObject()) {
10907 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010908 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10909 isolate->factory()->empty_string(),
10910 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010911 go_between->set_context(*context);
10912 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 isolate->factory()->NewFunctionContext(
10914 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010915 context->set_extension(JSObject::cast(*additional_context));
10916 is_global = false;
10917 }
10918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010920 // Currently, the eval code will be executed in non-strict mode,
10921 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010922 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010923 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010924 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 Handle<JSFunction>(
10927 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10928 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010929
10930 // Invoke the result of the compilation to get the evaluation function.
10931 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 Handle<Object> result =
10934 Execution::Call(compiled_function, receiver, 0, NULL,
10935 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010936 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937 return *result;
10938}
10939
10940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010941static MaybeObject* Runtime_DebugGetLoadedScripts(RUNTIME_CALLING_CONVENTION) {
10942 RUNTIME_GET_ISOLATE;
10943 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010944 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010947 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948
10949 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010950 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010951 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10952 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10953 // because using
10954 // instances->set(i, *GetScriptWrapper(script))
10955 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10956 // already have deferenced the instances handle.
10957 Handle<JSValue> wrapper = GetScriptWrapper(script);
10958 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 }
10960
10961 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 Handle<JSObject> result =
10963 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 Handle<JSArray>::cast(result)->SetContent(*instances);
10965 return *result;
10966}
10967
10968
10969// Helper function used by Runtime_DebugReferencedBy below.
10970static int DebugReferencedBy(JSObject* target,
10971 Object* instance_filter, int max_references,
10972 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 JSFunction* arguments_function) {
10974 NoHandleAllocation ha;
10975 AssertNoAllocation no_alloc;
10976
10977 // Iterate the heap.
10978 int count = 0;
10979 JSObject* last = NULL;
10980 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010981 HeapObject* heap_obj = NULL;
10982 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 (max_references == 0 || count < max_references)) {
10984 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985 if (heap_obj->IsJSObject()) {
10986 // Skip context extension objects and argument arrays as these are
10987 // checked in the context of functions using them.
10988 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010989 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 obj->map()->constructor() == arguments_function) {
10991 continue;
10992 }
10993
10994 // Check if the JS object has a reference to the object looked for.
10995 if (obj->ReferencesObject(target)) {
10996 // Check instance filter if supplied. This is normally used to avoid
10997 // references from mirror objects (see Runtime_IsInPrototypeChain).
10998 if (!instance_filter->IsUndefined()) {
10999 Object* V = obj;
11000 while (true) {
11001 Object* prototype = V->GetPrototype();
11002 if (prototype->IsNull()) {
11003 break;
11004 }
11005 if (instance_filter == prototype) {
11006 obj = NULL; // Don't add this object.
11007 break;
11008 }
11009 V = prototype;
11010 }
11011 }
11012
11013 if (obj != NULL) {
11014 // Valid reference found add to instance array if supplied an update
11015 // count.
11016 if (instances != NULL && count < instances_size) {
11017 instances->set(count, obj);
11018 }
11019 last = obj;
11020 count++;
11021 }
11022 }
11023 }
11024 }
11025
11026 // Check for circular reference only. This can happen when the object is only
11027 // referenced from mirrors and has a circular reference in which case the
11028 // object is not really alive and would have been garbage collected if not
11029 // referenced from the mirror.
11030 if (count == 1 && last == target) {
11031 count = 0;
11032 }
11033
11034 // Return the number of referencing objects found.
11035 return count;
11036}
11037
11038
11039// Scan the heap for objects with direct references to an object
11040// args[0]: the object to find references to
11041// args[1]: constructor function for instances to exclude (Mirror)
11042// args[2]: the the maximum number of objects to return
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043static MaybeObject* Runtime_DebugReferencedBy(RUNTIME_CALLING_CONVENTION) {
11044 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045 ASSERT(args.length() == 3);
11046
11047 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011049
11050 // Check parameters.
11051 CONVERT_CHECKED(JSObject, target, args[0]);
11052 Object* instance_filter = args[1];
11053 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11054 instance_filter->IsJSObject());
11055 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11056 RUNTIME_ASSERT(max_references >= 0);
11057
11058 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011059 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 JSFunction* arguments_function =
11062 JSFunction::cast(arguments_boilerplate->map()->constructor());
11063
11064 // Get the number of referencing objects.
11065 int count;
11066 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011067 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011068
11069 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011070 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011071 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011072 if (!maybe_object->ToObject(&object)) return maybe_object;
11073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011074 FixedArray* instances = FixedArray::cast(object);
11075
11076 // Fill the referencing objects.
11077 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011078 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079
11080 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011081 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011082 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11083 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011084 if (!maybe_result->ToObject(&result)) return maybe_result;
11085 }
11086 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011087 return result;
11088}
11089
11090
11091// Helper function used by Runtime_DebugConstructedBy below.
11092static int DebugConstructedBy(JSFunction* constructor, int max_references,
11093 FixedArray* instances, int instances_size) {
11094 AssertNoAllocation no_alloc;
11095
11096 // Iterate the heap.
11097 int count = 0;
11098 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011099 HeapObject* heap_obj = NULL;
11100 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101 (max_references == 0 || count < max_references)) {
11102 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011103 if (heap_obj->IsJSObject()) {
11104 JSObject* obj = JSObject::cast(heap_obj);
11105 if (obj->map()->constructor() == constructor) {
11106 // Valid reference found add to instance array if supplied an update
11107 // count.
11108 if (instances != NULL && count < instances_size) {
11109 instances->set(count, obj);
11110 }
11111 count++;
11112 }
11113 }
11114 }
11115
11116 // Return the number of referencing objects found.
11117 return count;
11118}
11119
11120
11121// Scan the heap for objects constructed by a specific function.
11122// args[0]: the constructor to find instances of
11123// args[1]: the the maximum number of objects to return
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124static MaybeObject* Runtime_DebugConstructedBy(RUNTIME_CALLING_CONVENTION) {
11125 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126 ASSERT(args.length() == 2);
11127
11128 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130
11131 // Check parameters.
11132 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11133 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11134 RUNTIME_ASSERT(max_references >= 0);
11135
11136 // Get the number of referencing objects.
11137 int count;
11138 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11139
11140 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011141 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011143 if (!maybe_object->ToObject(&object)) return maybe_object;
11144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 FixedArray* instances = FixedArray::cast(object);
11146
11147 // Fill the referencing objects.
11148 count = DebugConstructedBy(constructor, max_references, instances, count);
11149
11150 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011151 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011152 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11153 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011154 if (!maybe_result->ToObject(&result)) return maybe_result;
11155 }
11156 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157 return result;
11158}
11159
11160
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011161// Find the effective prototype object as returned by __proto__.
11162// args[0]: the object to find the prototype for.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163static MaybeObject* Runtime_DebugGetPrototype(RUNTIME_CALLING_CONVENTION) {
11164 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011165 ASSERT(args.length() == 1);
11166
11167 CONVERT_CHECKED(JSObject, obj, args[0]);
11168
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011169 // Use the __proto__ accessor.
11170 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171}
11172
11173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011174static MaybeObject* Runtime_SystemBreak(RUNTIME_CALLING_CONVENTION) {
11175 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +000011176 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011177 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011178 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179}
11180
11181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011182static MaybeObject* Runtime_DebugDisassembleFunction(
11183 RUNTIME_CALLING_CONVENTION) {
11184 RUNTIME_GET_ISOLATE;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011185#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011187 ASSERT(args.length() == 1);
11188 // Get the function and make sure it is compiled.
11189 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011190 Handle<SharedFunctionInfo> shared(func->shared());
11191 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011192 return Failure::Exception();
11193 }
11194 func->code()->PrintLn();
11195#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011196 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011197}
ager@chromium.org9085a012009-05-11 19:22:57 +000011198
11199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200static MaybeObject* Runtime_DebugDisassembleConstructor(
11201 RUNTIME_CALLING_CONVENTION) {
11202 RUNTIME_GET_ISOLATE;
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011203#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011205 ASSERT(args.length() == 1);
11206 // Get the function and make sure it is compiled.
11207 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011208 Handle<SharedFunctionInfo> shared(func->shared());
11209 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011210 return Failure::Exception();
11211 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011212 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011213#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011215}
11216
11217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218static MaybeObject* Runtime_FunctionGetInferredName(
11219 RUNTIME_CALLING_CONVENTION) {
11220 RUNTIME_GET_ISOLATE;
ager@chromium.org9085a012009-05-11 19:22:57 +000011221 NoHandleAllocation ha;
11222 ASSERT(args.length() == 1);
11223
11224 CONVERT_CHECKED(JSFunction, f, args[0]);
11225 return f->shared()->inferred_name();
11226}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011227
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011228
11229static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011230 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011231 AssertNoAllocation no_allocations;
11232
11233 int counter = 0;
11234 int buffer_size = buffer->length();
11235 HeapIterator iterator;
11236 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11237 ASSERT(obj != NULL);
11238 if (!obj->IsSharedFunctionInfo()) {
11239 continue;
11240 }
11241 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11242 if (shared->script() != script) {
11243 continue;
11244 }
11245 if (counter < buffer_size) {
11246 buffer->set(counter, shared);
11247 }
11248 counter++;
11249 }
11250 return counter;
11251}
11252
11253// For a script finds all SharedFunctionInfo's in the heap that points
11254// to this script. Returns JSArray of SharedFunctionInfo wrapped
11255// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011256static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011257 RUNTIME_CALLING_CONVENTION) {
11258 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011259 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011260 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011261 CONVERT_CHECKED(JSValue, script_value, args[0]);
11262
11263 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11264
11265 const int kBufferSize = 32;
11266
11267 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011268 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011269 int number = FindSharedFunctionInfosForScript(*script, *array);
11270 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011272 FindSharedFunctionInfosForScript(*script, *array);
11273 }
11274
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011275 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011276 result->set_length(Smi::FromInt(number));
11277
11278 LiveEdit::WrapSharedFunctionInfos(result);
11279
11280 return *result;
11281}
11282
11283// For a script calculates compilation information about all its functions.
11284// The script source is explicitly specified by the second argument.
11285// The source of the actual script is not used, however it is important that
11286// all generated code keeps references to this particular instance of script.
11287// Returns a JSArray of compilation infos. The array is ordered so that
11288// each function with all its descendant is always stored in a continues range
11289// with the function itself going first. The root function is a script function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011290static MaybeObject* Runtime_LiveEditGatherCompileInfo(
11291 RUNTIME_CALLING_CONVENTION) {
11292 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011293 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011295 CONVERT_CHECKED(JSValue, script, args[0]);
11296 CONVERT_ARG_CHECKED(String, source, 1);
11297 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11298
11299 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011302 return Failure::Exception();
11303 }
11304
11305 return result;
11306}
11307
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011308// Changes the source of the script to a new_source.
11309// If old_script_name is provided (i.e. is a String), also creates a copy of
11310// the script with its original source and sends notification to debugger.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311static MaybeObject* Runtime_LiveEditReplaceScript(RUNTIME_CALLING_CONVENTION) {
11312 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011313 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011315 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11316 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011317 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011318
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011319 CONVERT_CHECKED(Script, original_script_pointer,
11320 original_script_value->value());
11321 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011322
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011323 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11324 new_source,
11325 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011326
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011327 if (old_script->IsScript()) {
11328 Handle<Script> script_handle(Script::cast(old_script));
11329 return *(GetScriptWrapper(script_handle));
11330 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011331 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011332 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011333}
11334
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(
11337 RUNTIME_CALLING_CONVENTION) {
11338 RUNTIME_GET_ISOLATE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011339 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011341 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11342 return LiveEdit::FunctionSourceUpdated(shared_info);
11343}
11344
11345
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011346// Replaces code of SharedFunctionInfo with a new one.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347static MaybeObject* Runtime_LiveEditReplaceFunctionCode(
11348 RUNTIME_CALLING_CONVENTION) {
11349 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011350 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011352 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11353 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11354
ager@chromium.orgac091b72010-05-05 07:34:42 +000011355 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011356}
11357
11358// Connects SharedFunctionInfo to another script.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011359static MaybeObject* Runtime_LiveEditFunctionSetScript(
11360 RUNTIME_CALLING_CONVENTION) {
11361 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011362 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363 HandleScope scope(isolate);
11364 Handle<Object> function_object(args[0], isolate);
11365 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011366
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011367 if (function_object->IsJSValue()) {
11368 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11369 if (script_object->IsJSValue()) {
11370 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011372 }
11373
11374 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11375 } else {
11376 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11377 // and we check it in this function.
11378 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011381}
11382
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011383
11384// In a code of a parent function replaces original function as embedded object
11385// with a substitution one.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011386static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(
11387 RUNTIME_CALLING_CONVENTION) {
11388 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011389 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011390 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011391
11392 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11393 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11394 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11395
11396 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11397 subst_wrapper);
11398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011399 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011400}
11401
11402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011403// Updates positions of a shared function info (first parameter) according
11404// to script source change. Text change is described in second parameter as
11405// array of groups of 3 numbers:
11406// (change_begin, change_end, change_end_new_position).
11407// Each group describes a change in text; groups are sorted by change_begin.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408static MaybeObject* Runtime_LiveEditPatchFunctionPositions(
11409 RUNTIME_CALLING_CONVENTION) {
11410 RUNTIME_GET_ISOLATE;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011411 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011413 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11414 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11415
ager@chromium.orgac091b72010-05-05 07:34:42 +000011416 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011417}
11418
11419
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011420// For array of SharedFunctionInfo's (each wrapped in JSValue)
11421// checks that none of them have activations on stacks (of any thread).
11422// Returns array of the same length with corresponding results of
11423// LiveEdit::FunctionPatchabilityStatus type.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011424static MaybeObject* Runtime_LiveEditCheckAndDropActivations(
11425 RUNTIME_CALLING_CONVENTION) {
11426 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +000011427 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011428 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011429 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011430 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011431
ager@chromium.org357bf652010-04-12 11:30:10 +000011432 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011433}
11434
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011435// Compares 2 strings line-by-line, then token-wise and returns diff in form
11436// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11437// of diff chunks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438static MaybeObject* Runtime_LiveEditCompareStrings(RUNTIME_CALLING_CONVENTION) {
11439 RUNTIME_GET_ISOLATE;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011440 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011441 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011442 CONVERT_ARG_CHECKED(String, s1, 0);
11443 CONVERT_ARG_CHECKED(String, s2, 1);
11444
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011445 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011446}
11447
11448
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011449// A testing entry. Returns statement position which is the closest to
11450// source_position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011451static MaybeObject* Runtime_GetFunctionCodePositionFromSource(
11452 RUNTIME_CALLING_CONVENTION) {
11453 RUNTIME_GET_ISOLATE;
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011454 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011456 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11457 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011459 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011460
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011461 if (code->kind() != Code::FUNCTION &&
11462 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011464 }
11465
11466 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011467 int closest_pc = 0;
11468 int distance = kMaxInt;
11469 while (!it.done()) {
11470 int statement_position = static_cast<int>(it.rinfo()->data());
11471 // Check if this break point is closer that what was previously found.
11472 if (source_position <= statement_position &&
11473 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011474 closest_pc =
11475 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011476 distance = statement_position - source_position;
11477 // Check whether we can't get any closer.
11478 if (distance == 0) break;
11479 }
11480 it.next();
11481 }
11482
11483 return Smi::FromInt(closest_pc);
11484}
11485
11486
ager@chromium.org357bf652010-04-12 11:30:10 +000011487// Calls specified function with or without entering the debugger.
11488// This is used in unit tests to run code as if debugger is entered or simply
11489// to have a stack with C++ frame in the middle.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011490static MaybeObject* Runtime_ExecuteInDebugContext(RUNTIME_CALLING_CONVENTION) {
11491 RUNTIME_GET_ISOLATE;
ager@chromium.org357bf652010-04-12 11:30:10 +000011492 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011493 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011494 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11495 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11496
11497 Handle<Object> result;
11498 bool pending_exception;
11499 {
11500 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011501 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011502 &pending_exception);
11503 } else {
11504 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011506 &pending_exception);
11507 }
11508 }
11509 if (!pending_exception) {
11510 return *result;
11511 } else {
11512 return Failure::Exception();
11513 }
11514}
11515
11516
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011517// Sets a v8 flag.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518static MaybeObject* Runtime_SetFlags(RUNTIME_CALLING_CONVENTION) {
11519 RUNTIME_GET_ISOLATE;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011520 CONVERT_CHECKED(String, arg, args[0]);
11521 SmartPointer<char> flags =
11522 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11523 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011525}
11526
11527
11528// Performs a GC.
11529// Presently, it only does a full GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530static MaybeObject* Runtime_CollectGarbage(RUNTIME_CALLING_CONVENTION) {
11531 RUNTIME_GET_ISOLATE;
11532 isolate->heap()->CollectAllGarbage(true);
11533 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011534}
11535
11536
11537// Gets the current heap usage.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011538static MaybeObject* Runtime_GetHeapUsage(RUNTIME_CALLING_CONVENTION) {
11539 RUNTIME_GET_ISOLATE;
11540 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011541 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011543 }
11544 return Smi::FromInt(usage);
11545}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011546
11547
11548// Captures a live object list from the present heap.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011549static MaybeObject* Runtime_HasLOLEnabled(RUNTIME_CALLING_CONVENTION) {
11550 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011551#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011553#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011555#endif
11556}
11557
11558
11559// Captures a live object list from the present heap.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560static MaybeObject* Runtime_CaptureLOL(RUNTIME_CALLING_CONVENTION) {
11561 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011562#ifdef LIVE_OBJECT_LIST
11563 return LiveObjectList::Capture();
11564#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011566#endif
11567}
11568
11569
11570// Deletes the specified live object list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571static MaybeObject* Runtime_DeleteLOL(RUNTIME_CALLING_CONVENTION) {
11572 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011573#ifdef LIVE_OBJECT_LIST
11574 CONVERT_SMI_CHECKED(id, args[0]);
11575 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 return success ? isolate->heap()->true_value() :
11577 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011578#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011579 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011580#endif
11581}
11582
11583
11584// Generates the response to a debugger request for a dump of the objects
11585// contained in the difference between the captured live object lists
11586// specified by id1 and id2.
11587// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11588// dumped.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011589static MaybeObject* Runtime_DumpLOL(RUNTIME_CALLING_CONVENTION) {
11590 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011591#ifdef LIVE_OBJECT_LIST
11592 HandleScope scope;
11593 CONVERT_SMI_CHECKED(id1, args[0]);
11594 CONVERT_SMI_CHECKED(id2, args[1]);
11595 CONVERT_SMI_CHECKED(start, args[2]);
11596 CONVERT_SMI_CHECKED(count, args[3]);
11597 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11598 EnterDebugger enter_debugger;
11599 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11600#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011602#endif
11603}
11604
11605
11606// Gets the specified object as requested by the debugger.
11607// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608static MaybeObject* Runtime_GetLOLObj(RUNTIME_CALLING_CONVENTION) {
11609 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011610#ifdef LIVE_OBJECT_LIST
11611 CONVERT_SMI_CHECKED(obj_id, args[0]);
11612 Object* result = LiveObjectList::GetObj(obj_id);
11613 return result;
11614#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011616#endif
11617}
11618
11619
11620// Gets the obj id for the specified address if valid.
11621// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011622static MaybeObject* Runtime_GetLOLObjId(RUNTIME_CALLING_CONVENTION) {
11623 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011624#ifdef LIVE_OBJECT_LIST
11625 HandleScope scope;
11626 CONVERT_ARG_CHECKED(String, address, 0);
11627 Object* result = LiveObjectList::GetObjId(address);
11628 return result;
11629#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011631#endif
11632}
11633
11634
11635// Gets the retainers that references the specified object alive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636static MaybeObject* Runtime_GetLOLObjRetainers(RUNTIME_CALLING_CONVENTION) {
11637 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011638#ifdef LIVE_OBJECT_LIST
11639 HandleScope scope;
11640 CONVERT_SMI_CHECKED(obj_id, args[0]);
11641 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11642 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11643 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11644 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11645 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11646
11647 Handle<JSObject> instance_filter;
11648 if (args[1]->IsJSObject()) {
11649 instance_filter = args.at<JSObject>(1);
11650 }
11651 bool verbose = false;
11652 if (args[2]->IsBoolean()) {
11653 verbose = args[2]->IsTrue();
11654 }
11655 int start = 0;
11656 if (args[3]->IsSmi()) {
11657 start = Smi::cast(args[3])->value();
11658 }
11659 int limit = Smi::kMaxValue;
11660 if (args[4]->IsSmi()) {
11661 limit = Smi::cast(args[4])->value();
11662 }
11663
11664 return LiveObjectList::GetObjRetainers(obj_id,
11665 instance_filter,
11666 verbose,
11667 start,
11668 limit,
11669 filter_obj);
11670#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011672#endif
11673}
11674
11675
11676// Gets the reference path between 2 objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677static MaybeObject* Runtime_GetLOLPath(RUNTIME_CALLING_CONVENTION) {
11678 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011679#ifdef LIVE_OBJECT_LIST
11680 HandleScope scope;
11681 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11682 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11683 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11684
11685 Handle<JSObject> instance_filter;
11686 if (args[2]->IsJSObject()) {
11687 instance_filter = args.at<JSObject>(2);
11688 }
11689
11690 Object* result =
11691 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11692 return result;
11693#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011695#endif
11696}
11697
11698
11699// Generates the response to a debugger request for a list of all
11700// previously captured live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701static MaybeObject* Runtime_InfoLOL(RUNTIME_CALLING_CONVENTION) {
11702 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011703#ifdef LIVE_OBJECT_LIST
11704 CONVERT_SMI_CHECKED(start, args[0]);
11705 CONVERT_SMI_CHECKED(count, args[1]);
11706 return LiveObjectList::Info(start, count);
11707#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011709#endif
11710}
11711
11712
11713// Gets a dump of the specified object as requested by the debugger.
11714// This is only used for obj ids shown in live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715static MaybeObject* Runtime_PrintLOLObj(RUNTIME_CALLING_CONVENTION) {
11716 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011717#ifdef LIVE_OBJECT_LIST
11718 HandleScope scope;
11719 CONVERT_SMI_CHECKED(obj_id, args[0]);
11720 Object* result = LiveObjectList::PrintObj(obj_id);
11721 return result;
11722#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011723 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011724#endif
11725}
11726
11727
11728// Resets and releases all previously captured live object lists.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729static MaybeObject* Runtime_ResetLOL(RUNTIME_CALLING_CONVENTION) {
11730 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011731#ifdef LIVE_OBJECT_LIST
11732 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011734#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011736#endif
11737}
11738
11739
11740// Generates the response to a debugger request for a summary of the types
11741// of objects in the difference between the captured live object lists
11742// specified by id1 and id2.
11743// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11744// summarized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011745static MaybeObject* Runtime_SummarizeLOL(RUNTIME_CALLING_CONVENTION) {
11746 RUNTIME_GET_ISOLATE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011747#ifdef LIVE_OBJECT_LIST
11748 HandleScope scope;
11749 CONVERT_SMI_CHECKED(id1, args[0]);
11750 CONVERT_SMI_CHECKED(id2, args[1]);
11751 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11752
11753 EnterDebugger enter_debugger;
11754 return LiveObjectList::Summarize(id1, id2, filter_obj);
11755#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011756 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011757#endif
11758}
11759
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011760#endif // ENABLE_DEBUGGER_SUPPORT
11761
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011762
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011763#ifdef ENABLE_LOGGING_AND_PROFILING
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011764static MaybeObject* Runtime_ProfilerResume(RUNTIME_CALLING_CONVENTION) {
11765 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011766 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011767 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011768
11769 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011770 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11771 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011772 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011773}
11774
11775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776static MaybeObject* Runtime_ProfilerPause(RUNTIME_CALLING_CONVENTION) {
11777 RUNTIME_GET_ISOLATE;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011778 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011779 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011780
11781 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011782 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11783 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011785}
11786
11787#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789// Finds the script object from the script data. NOTE: This operation uses
11790// heap traversal to find the function generated for the source position
11791// for the requested break point. For lazily compiled functions several heap
11792// traversals might be required rendering this operation as a rather slow
11793// operation. However for setting break points which is normally done through
11794// some kind of user interaction the performance is not crucial.
11795static Handle<Object> Runtime_GetScriptFromScriptName(
11796 Handle<String> script_name) {
11797 // Scan the heap for Script objects to find the script with the requested
11798 // script data.
11799 Handle<Script> script;
11800 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011801 HeapObject* obj = NULL;
11802 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803 // If a script is found check if it has the script data requested.
11804 if (obj->IsScript()) {
11805 if (Script::cast(obj)->name()->IsString()) {
11806 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11807 script = Handle<Script>(Script::cast(obj));
11808 }
11809 }
11810 }
11811 }
11812
11813 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815
11816 // Return the script found.
11817 return GetScriptWrapper(script);
11818}
11819
11820
11821// Get the script object from script data. NOTE: Regarding performance
11822// see the NOTE for GetScriptFromScriptData.
11823// args[0]: script data for the script to find the source for
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011824static MaybeObject* Runtime_GetScript(RUNTIME_CALLING_CONVENTION) {
11825 RUNTIME_GET_ISOLATE;
11826 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827
11828 ASSERT(args.length() == 1);
11829
11830 CONVERT_CHECKED(String, script_name, args[0]);
11831
11832 // Find the requested script.
11833 Handle<Object> result =
11834 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11835 return *result;
11836}
11837
11838
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011839// Determines whether the given stack frame should be displayed in
11840// a stack trace. The caller is the error constructor that asked
11841// for the stack trace to be collected. The first time a construct
11842// call to this function is encountered it is skipped. The seen_caller
11843// in/out parameter is used to remember if the caller has been seen
11844// yet.
11845static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11846 bool* seen_caller) {
11847 // Only display JS frames.
11848 if (!raw_frame->is_java_script())
11849 return false;
11850 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11851 Object* raw_fun = frame->function();
11852 // Not sure when this can happen but skip it just in case.
11853 if (!raw_fun->IsJSFunction())
11854 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011855 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011856 *seen_caller = true;
11857 return false;
11858 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011859 // Skip all frames until we've seen the caller. Also, skip the most
11860 // obvious builtin calls. Some builtin calls (such as Number.ADD
11861 // which is invoked using 'call') are very difficult to recognize
11862 // so we're leaving them in for now.
11863 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011864}
11865
11866
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011867// Collect the raw data for a stack trace. Returns an array of 4
11868// element segments each containing a receiver, function, code and
11869// native code offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
11871 RUNTIME_GET_ISOLATE;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011872 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011873 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011874 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 HandleScope scope(isolate);
11877 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011878
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011879 limit = Max(limit, 0); // Ensure that limit is not negative.
11880 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011881 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011883
11884 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011885 // If the caller parameter is a function we skip frames until we're
11886 // under it before starting to collect.
11887 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011888 int cursor = 0;
11889 int frames_seen = 0;
11890 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011891 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011892 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011893 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011894 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011895 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11896 frame->Summarize(&frames);
11897 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011898 if (cursor + 4 > elements->length()) {
11899 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11900 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011902 for (int i = 0; i < cursor; i++) {
11903 new_elements->set(i, elements->get(i));
11904 }
11905 elements = new_elements;
11906 }
11907 ASSERT(cursor + 4 <= elements->length());
11908
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011909 Handle<Object> recv = frames[i].receiver();
11910 Handle<JSFunction> fun = frames[i].function();
11911 Handle<Code> code = frames[i].code();
11912 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011913 elements->set(cursor++, *recv);
11914 elements->set(cursor++, *fun);
11915 elements->set(cursor++, *code);
11916 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011917 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011918 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011919 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011920 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011922 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011923 return *result;
11924}
11925
11926
ager@chromium.org3811b432009-10-28 14:53:37 +000011927// Returns V8 version as a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011928static MaybeObject* Runtime_GetV8Version(RUNTIME_CALLING_CONVENTION) {
11929 RUNTIME_GET_ISOLATE;
ager@chromium.org3811b432009-10-28 14:53:37 +000011930 ASSERT_EQ(args.length(), 0);
11931
11932 NoHandleAllocation ha;
11933
11934 const char* version_string = v8::V8::GetVersion();
11935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11937 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011938}
11939
11940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941static MaybeObject* Runtime_Abort(RUNTIME_CALLING_CONVENTION) {
11942 RUNTIME_GET_ISOLATE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011943 ASSERT(args.length() == 2);
11944 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11945 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947 OS::Abort();
11948 UNREACHABLE();
11949 return NULL;
11950}
11951
11952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953static MaybeObject* Runtime_GetFromCache(RUNTIME_CALLING_CONVENTION) {
11954 RUNTIME_GET_ISOLATE;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011955 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011956 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011957 Object* key = args[1];
11958
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011959 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011960 Object* o = cache->get(finger_index);
11961 if (o == key) {
11962 // The fastest case: hit the same place again.
11963 return cache->get(finger_index + 1);
11964 }
11965
11966 for (int i = finger_index - 2;
11967 i >= JSFunctionResultCache::kEntriesIndex;
11968 i -= 2) {
11969 o = cache->get(i);
11970 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011971 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011972 return cache->get(i + 1);
11973 }
11974 }
11975
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011976 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011977 ASSERT(size <= cache->length());
11978
11979 for (int i = size - 2; i > finger_index; i -= 2) {
11980 o = cache->get(i);
11981 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011982 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011983 return cache->get(i + 1);
11984 }
11985 }
11986
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011987 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011988 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011989
11990 Handle<JSFunctionResultCache> cache_handle(cache);
11991 Handle<Object> key_handle(key);
11992 Handle<Object> value;
11993 {
11994 Handle<JSFunction> factory(JSFunction::cast(
11995 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11996 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011998 // This handle is nor shared, nor used later, so it's safe.
11999 Object** argv[] = { key_handle.location() };
12000 bool pending_exception = false;
12001 value = Execution::Call(factory,
12002 receiver,
12003 1,
12004 argv,
12005 &pending_exception);
12006 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012007 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012008
12009#ifdef DEBUG
12010 cache_handle->JSFunctionResultCacheVerify();
12011#endif
12012
12013 // Function invocation may have cleared the cache. Reread all the data.
12014 finger_index = cache_handle->finger_index();
12015 size = cache_handle->size();
12016
12017 // If we have spare room, put new data into it, otherwise evict post finger
12018 // entry which is likely to be the least recently used.
12019 int index = -1;
12020 if (size < cache_handle->length()) {
12021 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12022 index = size;
12023 } else {
12024 index = finger_index + JSFunctionResultCache::kEntrySize;
12025 if (index == cache_handle->length()) {
12026 index = JSFunctionResultCache::kEntriesIndex;
12027 }
12028 }
12029
12030 ASSERT(index % 2 == 0);
12031 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12032 ASSERT(index < cache_handle->length());
12033
12034 cache_handle->set(index, *key_handle);
12035 cache_handle->set(index + 1, *value);
12036 cache_handle->set_finger_index(index);
12037
12038#ifdef DEBUG
12039 cache_handle->JSFunctionResultCacheVerify();
12040#endif
12041
12042 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012043}
12044
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012045
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012046static MaybeObject* Runtime_NewMessageObject(RUNTIME_CALLING_CONVENTION) {
12047 RUNTIME_GET_ISOLATE;
12048 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012049 CONVERT_ARG_CHECKED(String, type, 0);
12050 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012051 return *isolate->factory()->NewJSMessageObject(
12052 type,
12053 arguments,
12054 0,
12055 0,
12056 isolate->factory()->undefined_value(),
12057 isolate->factory()->undefined_value(),
12058 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012059}
12060
12061
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062static MaybeObject* Runtime_MessageGetType(RUNTIME_CALLING_CONVENTION) {
12063 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012064 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12065 return message->type();
12066}
12067
12068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012069static MaybeObject* Runtime_MessageGetArguments(RUNTIME_CALLING_CONVENTION) {
12070 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012071 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12072 return message->arguments();
12073}
12074
12075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012076static MaybeObject* Runtime_MessageGetStartPosition(
12077 RUNTIME_CALLING_CONVENTION) {
12078 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012079 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12080 return Smi::FromInt(message->start_position());
12081}
12082
12083
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012084static MaybeObject* Runtime_MessageGetScript(RUNTIME_CALLING_CONVENTION) {
12085 RUNTIME_GET_ISOLATE;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012086 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12087 return message->script();
12088}
12089
12090
kasper.lund44510672008-07-25 07:37:58 +000012091#ifdef DEBUG
12092// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12093// Exclude the code in release mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094static MaybeObject* Runtime_ListNatives(RUNTIME_CALLING_CONVENTION) {
12095 RUNTIME_GET_ISOLATE;
mads.s.ager31e71382008-08-13 09:32:07 +000012096 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012098#define COUNT_ENTRY(Name, argc, ressize) + 1
12099 int entry_count = 0
12100 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12101 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12102 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12103#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104 Factory* factory = isolate->factory();
12105 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012107 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012108#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012109 { \
12110 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012111 Handle<String> name; \
12112 /* Inline runtime functions have an underscore in front of the name. */ \
12113 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012115 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12116 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012117 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012118 Vector<const char>(#Name, StrLength(#Name))); \
12119 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012120 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012121 pair_elements->set(0, *name); \
12122 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012124 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012126 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012128 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012129 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012130 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012132 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012133 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 return *result;
12135}
kasper.lund44510672008-07-25 07:37:58 +000012136#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137
12138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139static MaybeObject* Runtime_Log(RUNTIME_CALLING_CONVENTION) {
12140 RUNTIME_GET_ISOLATE;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012141 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012142 CONVERT_CHECKED(String, format, args[0]);
12143 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012144 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 LOGGER->LogRuntime(chars, elms);
12146 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012147}
12148
12149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150static MaybeObject* Runtime_IS_VAR(RUNTIME_CALLING_CONVENTION) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151 UNREACHABLE(); // implemented as macro in the parser
12152 return NULL;
12153}
12154
12155
12156// ----------------------------------------------------------------------------
12157// Implementation of Runtime
12158
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012159#define F(name, number_of_args, result_size) \
12160 { Runtime::k##name, Runtime::RUNTIME, #name, \
12161 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012162
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012163
12164#define I(name, number_of_args, result_size) \
12165 { Runtime::kInline##name, Runtime::INLINE, \
12166 "_" #name, NULL, number_of_args, result_size },
12167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012170 INLINE_FUNCTION_LIST(I)
12171 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172};
12173
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012175MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12176 Object* dictionary) {
12177 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012178 ASSERT(dictionary != NULL);
12179 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12180 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012181 Object* name_symbol;
12182 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012184 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12185 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012186 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012187 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12188 String::cast(name_symbol),
12189 Smi::FromInt(i),
12190 PropertyDetails(NONE, NORMAL));
12191 if (!maybe_dictionary->ToObject(&dictionary)) {
12192 // Non-recoverable failure. Calling code must restart heap
12193 // initialization.
12194 return maybe_dictionary;
12195 }
12196 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012197 }
12198 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199}
12200
12201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12203 Heap* heap = name->GetHeap();
12204 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012205 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012206 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012207 int function_index = Smi::cast(smi_index)->value();
12208 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012209 }
12210 return NULL;
12211}
12212
12213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012215 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12216}
12217
12218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219void Runtime::PerformGC(Object* result) {
12220 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012221 if (failure->IsRetryAfterGC()) {
12222 // Try to do a garbage collection; ignore it if it fails. The C
12223 // entry stub will throw an out-of-memory exception in that case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012224 HEAP->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012225 } else {
12226 // Handle last resort GC and make sure to allow future allocations
12227 // to grow the heap without causing GCs (if possible).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 COUNTERS->gc_last_resort_from_js()->Increment();
12229 HEAP->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231}
12232
12233
12234} } // namespace v8::internal