blob: 44fe64620561ff5ac060583f7d078bebba2d2205 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002716 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004683 return isolate->heap()->NumberFromDouble(
4684 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685}
4686
4687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004688RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 NoHandleAllocation ha;
4690 ASSERT(args.length() == 1);
4691
4692 CONVERT_CHECKED(JSArray, codes, args[0]);
4693 int length = Smi::cast(codes->length())->value();
4694
4695 // Check if the string can be ASCII.
4696 int i;
4697 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698 Object* element;
4699 { MaybeObject* maybe_element = codes->GetElement(i);
4700 // We probably can't get an exception here, but just in order to enforce
4701 // the checking of inputs in the runtime calls we check here.
4702 if (!maybe_element->ToObject(&element)) return maybe_element;
4703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4705 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4706 break;
4707 }
4708
lrn@chromium.org303ada72010-10-27 09:33:13 +00004709 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 }
4715
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 Object* object = NULL;
4717 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 String* result = String::cast(object);
4719 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004720 Object* element;
4721 { MaybeObject* maybe_element = codes->GetElement(i);
4722 if (!maybe_element->ToObject(&element)) return maybe_element;
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004725 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 }
4727 return result;
4728}
4729
4730
4731// kNotEscaped is generated by the following:
4732//
4733// #!/bin/perl
4734// for (my $i = 0; $i < 256; $i++) {
4735// print "\n" if $i % 16 == 0;
4736// my $c = chr($i);
4737// my $escaped = 1;
4738// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4739// print $escaped ? "0, " : "1, ";
4740// }
4741
4742
4743static bool IsNotEscaped(uint16_t character) {
4744 // Only for 8 bit characters, the rest are always escaped (in a different way)
4745 ASSERT(character < 256);
4746 static const char kNotEscaped[256] = {
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4753 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4754 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 };
4764 return kNotEscaped[character] != 0;
4765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 const char hex_chars[] = "0123456789ABCDEF";
4770 NoHandleAllocation ha;
4771 ASSERT(args.length() == 1);
4772 CONVERT_CHECKED(String, source, args[0]);
4773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004774 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 int escaped_length = 0;
4777 int length = source->length();
4778 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004779 Access<StringInputBuffer> buffer(
4780 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 buffer->Reset(source);
4782 while (buffer->has_more()) {
4783 uint16_t character = buffer->GetNext();
4784 if (character >= 256) {
4785 escaped_length += 6;
4786 } else if (IsNotEscaped(character)) {
4787 escaped_length++;
4788 } else {
4789 escaped_length += 3;
4790 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004791 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004792 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004793 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004794 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 return Failure::OutOfMemoryException();
4796 }
4797 }
4798 }
4799 // No length change implies no change. Return original string if no change.
4800 if (escaped_length == length) {
4801 return source;
4802 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004803 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 { MaybeObject* maybe_o =
4805 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 String* destination = String::cast(o);
4809 int dest_position = 0;
4810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 Access<StringInputBuffer> buffer(
4812 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 buffer->Rewind();
4814 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004815 uint16_t chr = buffer->GetNext();
4816 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004817 destination->Set(dest_position, '%');
4818 destination->Set(dest_position+1, 'u');
4819 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4820 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4821 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4822 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004824 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004825 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 dest_position++;
4827 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004828 destination->Set(dest_position, '%');
4829 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4830 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 dest_position += 3;
4832 }
4833 }
4834 return destination;
4835}
4836
4837
4838static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4839 static const signed char kHexValue['g'] = {
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4844 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, 10, 11, 12, 13, 14, 15 };
4847
4848 if (character1 > 'f') return -1;
4849 int hi = kHexValue[character1];
4850 if (hi == -1) return -1;
4851 if (character2 > 'f') return -1;
4852 int lo = kHexValue[character2];
4853 if (lo == -1) return -1;
4854 return (hi << 4) + lo;
4855}
4856
4857
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 int i,
4860 int length,
4861 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 int32_t hi = 0;
4864 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 if (character == '%' &&
4866 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004867 source->Get(i + 1) == 'u' &&
4868 (hi = TwoDigitHex(source->Get(i + 2),
4869 source->Get(i + 3))) != -1 &&
4870 (lo = TwoDigitHex(source->Get(i + 4),
4871 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 *step = 6;
4873 return (hi << 8) + lo;
4874 } else if (character == '%' &&
4875 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004876 (lo = TwoDigitHex(source->Get(i + 1),
4877 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 *step = 3;
4879 return lo;
4880 } else {
4881 *step = 1;
4882 return character;
4883 }
4884}
4885
4886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 NoHandleAllocation ha;
4889 ASSERT(args.length() == 1);
4890 CONVERT_CHECKED(String, source, args[0]);
4891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004895 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896
4897 int unescaped_length = 0;
4898 for (int i = 0; i < length; unescaped_length++) {
4899 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004900 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 i += step;
4904 }
4905
4906 // No length change implies no change. Return original string if no change.
4907 if (unescaped_length == length)
4908 return source;
4909
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 { MaybeObject* maybe_o =
4912 ascii ?
4913 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4914 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 if (!maybe_o->ToObject(&o)) return maybe_o;
4916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 String* destination = String::cast(o);
4918
4919 int dest_position = 0;
4920 for (int i = 0; i < length; dest_position++) {
4921 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004922 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 i += step;
4924 }
4925 return destination;
4926}
4927
4928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929static const unsigned int kQuoteTableLength = 128u;
4930
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004931static const int kJsonQuotesCharactersPerEntry = 8;
4932static const char* const JsonQuotes =
4933 "\\u0000 \\u0001 \\u0002 \\u0003 "
4934 "\\u0004 \\u0005 \\u0006 \\u0007 "
4935 "\\b \\t \\n \\u000b "
4936 "\\f \\r \\u000e \\u000f "
4937 "\\u0010 \\u0011 \\u0012 \\u0013 "
4938 "\\u0014 \\u0015 \\u0016 \\u0017 "
4939 "\\u0018 \\u0019 \\u001a \\u001b "
4940 "\\u001c \\u001d \\u001e \\u001f "
4941 " ! \\\" # "
4942 "$ % & ' "
4943 "( ) * + "
4944 ", - . / "
4945 "0 1 2 3 "
4946 "4 5 6 7 "
4947 "8 9 : ; "
4948 "< = > ? "
4949 "@ A B C "
4950 "D E F G "
4951 "H I J K "
4952 "L M N O "
4953 "P Q R S "
4954 "T U V W "
4955 "X Y Z [ "
4956 "\\\\ ] ^ _ "
4957 "` a b c "
4958 "d e f g "
4959 "h i j k "
4960 "l m n o "
4961 "p q r s "
4962 "t u v w "
4963 "x y z { "
4964 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965
4966
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004967// For a string that is less than 32k characters it should always be
4968// possible to allocate it in new space.
4969static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4970
4971
4972// Doing JSON quoting cannot make the string more than this many times larger.
4973static const int kJsonQuoteWorstCaseBlowup = 6;
4974
4975
4976// Covers the entire ASCII range (all other characters are unchanged by JSON
4977// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004978static const byte JsonQuoteLengths[kQuoteTableLength] = {
4979 6, 6, 6, 6, 6, 6, 6, 6,
4980 2, 2, 2, 6, 2, 2, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 1, 1, 2, 1, 1, 1, 1, 1,
4984 1, 1, 1, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 2, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995};
4996
4997
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004998template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000
5001
5002template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5004 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005}
5006
5007
5008template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5010 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005011}
5012
5013
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005014template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5016 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005017 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005018 const Char* read_cursor = characters.start();
5019 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005020 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005021 int quoted_length = kSpaceForQuotes;
5022 while (read_cursor < end) {
5023 Char c = *(read_cursor++);
5024 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5025 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005027 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 }
5029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5031 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005032 Object* new_object;
5033 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 return new_alloc;
5035 }
5036 StringType* new_string = StringType::cast(new_object);
5037
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005038 Char* write_cursor = reinterpret_cast<Char*>(
5039 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005040 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041 *(write_cursor++) = '"';
5042
5043 read_cursor = characters.start();
5044 while (read_cursor < end) {
5045 Char c = *(read_cursor++);
5046 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5047 *(write_cursor++) = c;
5048 } else {
5049 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5050 const char* replacement = JsonQuotes +
5051 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5052 for (int i = 0; i < len; i++) {
5053 *write_cursor++ = *replacement++;
5054 }
5055 }
5056 }
5057 *(write_cursor++) = '"';
5058 return new_string;
5059}
5060
5061
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005062template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063static MaybeObject* QuoteJsonString(Isolate* isolate,
5064 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005067 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005068 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5069 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005071 }
5072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5074 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Object* new_object;
5076 if (!new_alloc->ToObject(&new_object)) {
5077 return new_alloc;
5078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080 // Even if our string is small enough to fit in new space we still have to
5081 // handle it being allocated in old space as may happen in the third
5082 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5083 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005085 }
5086 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005088
5089 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5090 Char* write_cursor = reinterpret_cast<Char*>(
5091 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005092 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005096 const Char* end = read_cursor + length;
5097 while (read_cursor < end) {
5098 Char c = *(read_cursor++);
5099 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5100 *(write_cursor++) = c;
5101 } else {
5102 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5103 const char* replacement = JsonQuotes +
5104 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5105 write_cursor[0] = replacement[0];
5106 if (len > 1) {
5107 write_cursor[1] = replacement[1];
5108 if (len > 2) {
5109 ASSERT(len == 6);
5110 write_cursor[2] = replacement[2];
5111 write_cursor[3] = replacement[3];
5112 write_cursor[4] = replacement[4];
5113 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114 }
5115 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005116 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117 }
5118 }
5119 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005120
5121 int final_length = static_cast<int>(
5122 write_cursor - reinterpret_cast<Char*>(
5123 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005124 isolate->heap()->new_space()->
5125 template ShrinkStringAtAllocationBoundary<StringType>(
5126 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127 return new_string;
5128}
5129
5130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005131RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 NoHandleAllocation ha;
5133 CONVERT_CHECKED(String, str, args[0]);
5134 if (!str->IsFlat()) {
5135 MaybeObject* try_flatten = str->TryFlatten();
5136 Object* flat;
5137 if (!try_flatten->ToObject(&flat)) {
5138 return try_flatten;
5139 }
5140 str = String::cast(flat);
5141 ASSERT(str->IsFlat());
5142 }
5143 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5145 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5148 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 }
5150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 NoHandleAllocation ha;
5155 CONVERT_CHECKED(String, str, args[0]);
5156 if (!str->IsFlat()) {
5157 MaybeObject* try_flatten = str->TryFlatten();
5158 Object* flat;
5159 if (!try_flatten->ToObject(&flat)) {
5160 return try_flatten;
5161 }
5162 str = String::cast(flat);
5163 ASSERT(str->IsFlat());
5164 }
5165 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5167 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005168 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5170 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171 }
5172}
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176
5177 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005178 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
lrn@chromium.org25156de2010-04-06 13:10:27 +00005182 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005183 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185}
5186
5187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 NoHandleAllocation ha;
5190 CONVERT_CHECKED(String, str, args[0]);
5191
5192 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005193 double value = StringToDouble(isolate->unicode_cache(),
5194 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195
5196 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005204 String* s,
5205 int length,
5206 int input_string_length,
5207 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 // We try this twice, once with the assumption that the result is no longer
5209 // than the input and, if that assumption breaks, again with the exact
5210 // length. This may not be pretty, but it is nicer than what was here before
5211 // and I hereby claim my vaffel-is.
5212 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 // Allocate the resulting string.
5214 //
5215 // NOTE: This assumes that the upper/lower case of an ascii
5216 // character is also ascii. This is currently the case, but it
5217 // might break in the future if we implement more context and locale
5218 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219 Object* o;
5220 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 ? isolate->heap()->AllocateRawAsciiString(length)
5222 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005223 if (!maybe_o->ToObject(&o)) return maybe_o;
5224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 String* result = String::cast(o);
5226 bool has_changed_character = false;
5227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 // Convert all characters to upper case, assuming that they will fit
5229 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005230 Access<StringInputBuffer> buffer(
5231 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005233 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 // We can assume that the string is not empty
5235 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005236 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005237 bool has_next = buffer->has_more();
5238 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 int char_length = mapping->get(current, next, chars);
5240 if (char_length == 0) {
5241 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005242 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 i++;
5244 } else if (char_length == 1) {
5245 // Common case: converting the letter resulted in one character.
5246 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005247 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 has_changed_character = true;
5249 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005250 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 // We've assumed that the result would be as long as the
5252 // input but here is a character that converts to several
5253 // characters. No matter, we calculate the exact length
5254 // of the result and try the whole thing again.
5255 //
5256 // Note that this leaves room for optimization. We could just
5257 // memcpy what we already have to the result string. Also,
5258 // the result string is the last object allocated we could
5259 // "realloc" it and probably, in the vast majority of cases,
5260 // extend the existing string to be able to hold the full
5261 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005262 int next_length = 0;
5263 if (has_next) {
5264 next_length = mapping->get(next, 0, chars);
5265 if (next_length == 0) next_length = 1;
5266 }
5267 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 while (buffer->has_more()) {
5269 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005270 // NOTE: we use 0 as the next character here because, while
5271 // the next character may affect what a character converts to,
5272 // it does not in any case affect the length of what it convert
5273 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 int char_length = mapping->get(current, 0, chars);
5275 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005276 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005278 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 return Failure::OutOfMemoryException();
5280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282 // Try again with the real length.
5283 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 } else {
5285 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 i++;
5288 }
5289 has_changed_character = true;
5290 }
5291 current = next;
5292 }
5293 if (has_changed_character) {
5294 return result;
5295 } else {
5296 // If we didn't actually change anything in doing the conversion
5297 // we simple return the result and let the converted string
5298 // become garbage; there is no reason to keep two identical strings
5299 // alive.
5300 return s;
5301 }
5302}
5303
5304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305namespace {
5306
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5308
5309
5310// Given a word and two range boundaries returns a word with high bit
5311// set in every byte iff the corresponding input byte was strictly in
5312// the range (m, n). All the other bits in the result are cleared.
5313// This function is only useful when it can be inlined and the
5314// boundaries are statically known.
5315// Requires: all bytes in the input word and the boundaries must be
5316// ascii (less than 0x7F).
5317static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5318 // Every byte in an ascii string is less than or equal to 0x7F.
5319 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5320 // Use strict inequalities since in edge cases the function could be
5321 // further simplified.
5322 ASSERT(0 < m && m < n && n < 0x7F);
5323 // Has high bit set in every w byte less than n.
5324 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5325 // Has high bit set in every w byte greater than m.
5326 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5327 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5328}
5329
5330
5331enum AsciiCaseConversion {
5332 ASCII_TO_LOWER,
5333 ASCII_TO_UPPER
5334};
5335
5336
5337template <AsciiCaseConversion dir>
5338struct FastAsciiConverter {
5339 static bool Convert(char* dst, char* src, int length) {
5340#ifdef DEBUG
5341 char* saved_dst = dst;
5342 char* saved_src = src;
5343#endif
5344 // We rely on the distance between upper and lower case letters
5345 // being a known power of 2.
5346 ASSERT('a' - 'A' == (1 << 5));
5347 // Boundaries for the range of input characters than require conversion.
5348 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5349 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5350 bool changed = false;
5351 char* const limit = src + length;
5352#ifdef V8_HOST_CAN_READ_UNALIGNED
5353 // Process the prefix of the input that requires no conversion one
5354 // (machine) word at a time.
5355 while (src <= limit - sizeof(uintptr_t)) {
5356 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5357 if (AsciiRangeMask(w, lo, hi) != 0) {
5358 changed = true;
5359 break;
5360 }
5361 *reinterpret_cast<uintptr_t*>(dst) = w;
5362 src += sizeof(uintptr_t);
5363 dst += sizeof(uintptr_t);
5364 }
5365 // Process the remainder of the input performing conversion when
5366 // required one word at a time.
5367 while (src <= limit - sizeof(uintptr_t)) {
5368 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5369 uintptr_t m = AsciiRangeMask(w, lo, hi);
5370 // The mask has high (7th) bit set in every byte that needs
5371 // conversion and we know that the distance between cases is
5372 // 1 << 5.
5373 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5374 src += sizeof(uintptr_t);
5375 dst += sizeof(uintptr_t);
5376 }
5377#endif
5378 // Process the last few bytes of the input (or the whole input if
5379 // unaligned access is not supported).
5380 while (src < limit) {
5381 char c = *src;
5382 if (lo < c && c < hi) {
5383 c ^= (1 << 5);
5384 changed = true;
5385 }
5386 *dst = c;
5387 ++src;
5388 ++dst;
5389 }
5390#ifdef DEBUG
5391 CheckConvert(saved_dst, saved_src, length, changed);
5392#endif
5393 return changed;
5394 }
5395
5396#ifdef DEBUG
5397 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5398 bool expected_changed = false;
5399 for (int i = 0; i < length; i++) {
5400 if (dst[i] == src[i]) continue;
5401 expected_changed = true;
5402 if (dir == ASCII_TO_LOWER) {
5403 ASSERT('A' <= src[i] && src[i] <= 'Z');
5404 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5405 } else {
5406 ASSERT(dir == ASCII_TO_UPPER);
5407 ASSERT('a' <= src[i] && src[i] <= 'z');
5408 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5409 }
5410 }
5411 ASSERT(expected_changed == changed);
5412 }
5413#endif
5414};
5415
5416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417struct ToLowerTraits {
5418 typedef unibrow::ToLowercase UnibrowConverter;
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421};
5422
5423
5424struct ToUpperTraits {
5425 typedef unibrow::ToUppercase UnibrowConverter;
5426
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005428};
5429
5430} // namespace
5431
5432
5433template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005436 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005437 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005440 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444 if (length == 0) return s;
5445
5446 // Simpler handling of ascii strings.
5447 //
5448 // NOTE: This assumes that the upper/lower case of an ascii
5449 // character is also ascii. This is currently the case, but it
5450 // might break in the future if we implement more context and locale
5451 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005452 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455 if (!maybe_o->ToObject(&o)) return maybe_o;
5456 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005457 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005459 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460 return has_changed_character ? result : s;
5461 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005464 { MaybeObject* maybe_answer =
5465 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5467 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 if (answer->IsSmi()) {
5469 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005471 ConvertCaseHelper(isolate,
5472 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5474 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005476 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477}
5478
5479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005481 return ConvertCase<ToLowerTraits>(
5482 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483}
5484
5485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005486RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005487 return ConvertCase<ToUpperTraits>(
5488 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489}
5490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005491
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005492static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5493 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5494}
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005498 NoHandleAllocation ha;
5499 ASSERT(args.length() == 3);
5500
5501 CONVERT_CHECKED(String, s, args[0]);
5502 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5503 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5504
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005505 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005506 int length = s->length();
5507
5508 int left = 0;
5509 if (trimLeft) {
5510 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5511 left++;
5512 }
5513 }
5514
5515 int right = length;
5516 if (trimRight) {
5517 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5518 right--;
5519 }
5520 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005521 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005522}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005524
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005525template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526void FindStringIndices(Isolate* isolate,
5527 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005528 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005529 ZoneList<int>* indices,
5530 unsigned int limit) {
5531 ASSERT(limit > 0);
5532 // Collect indices of pattern in subject, and the end-of-string index.
5533 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005535 int pattern_length = pattern.length();
5536 int index = 0;
5537 while (limit > 0) {
5538 index = search.Search(subject, index);
5539 if (index < 0) return;
5540 indices->Add(index);
5541 index += pattern_length;
5542 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005543 }
5544}
5545
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005547RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005549 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005550 CONVERT_ARG_CHECKED(String, subject, 0);
5551 CONVERT_ARG_CHECKED(String, pattern, 1);
5552 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5553
5554 int subject_length = subject->length();
5555 int pattern_length = pattern->length();
5556 RUNTIME_ASSERT(pattern_length > 0);
5557
5558 // The limit can be very large (0xffffffffu), but since the pattern
5559 // isn't empty, we can never create more parts than ~half the length
5560 // of the subject.
5561
5562 if (!subject->IsFlat()) FlattenString(subject);
5563
5564 static const int kMaxInitialListCapacity = 16;
5565
5566 ZoneScope scope(DELETE_ON_EXIT);
5567
5568 // Find (up to limit) indices of separator and end-of-string in subject
5569 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5570 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005571 if (!pattern->IsFlat()) FlattenString(pattern);
5572
5573 // No allocation block.
5574 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005575 AssertNoAllocation nogc;
5576 if (subject->IsAsciiRepresentation()) {
5577 Vector<const char> subject_vector = subject->ToAsciiVector();
5578 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005579 FindStringIndices(isolate,
5580 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005581 pattern->ToAsciiVector(),
5582 &indices,
5583 limit);
5584 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 FindStringIndices(isolate,
5586 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 pattern->ToUC16Vector(),
5588 &indices,
5589 limit);
5590 }
5591 } else {
5592 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5593 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005594 FindStringIndices(isolate,
5595 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005596 pattern->ToAsciiVector(),
5597 &indices,
5598 limit);
5599 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005600 FindStringIndices(isolate,
5601 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005602 pattern->ToUC16Vector(),
5603 &indices,
5604 limit);
5605 }
5606 }
5607 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005608
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005609 if (static_cast<uint32_t>(indices.length()) < limit) {
5610 indices.Add(subject_length);
5611 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005613 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614
5615 // Create JSArray of substrings separated by separator.
5616 int part_count = indices.length();
5617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005619 result->set_length(Smi::FromInt(part_count));
5620
5621 ASSERT(result->HasFastElements());
5622
5623 if (part_count == 1 && indices.at(0) == subject_length) {
5624 FixedArray::cast(result->elements())->set(0, *subject);
5625 return *result;
5626 }
5627
5628 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5629 int part_start = 0;
5630 for (int i = 0; i < part_count; i++) {
5631 HandleScope local_loop_handle;
5632 int part_end = indices.at(i);
5633 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005635 elements->set(i, *substring);
5636 part_start = part_end + pattern_length;
5637 }
5638
5639 return *result;
5640}
5641
5642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643// Copies ascii characters to the given fixed array looking up
5644// one-char strings in the cache. Gives up on the first char that is
5645// not in the cache and fills the remainder with smi zeros. Returns
5646// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static int CopyCachedAsciiCharsToArray(Heap* heap,
5648 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649 FixedArray* elements,
5650 int length) {
5651 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005652 FixedArray* ascii_cache = heap->single_character_string_cache();
5653 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005654 int i;
5655 for (i = 0; i < length; ++i) {
5656 Object* value = ascii_cache->get(chars[i]);
5657 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 elements->set(i, value, SKIP_WRITE_BARRIER);
5660 }
5661 if (i < length) {
5662 ASSERT(Smi::FromInt(0) == 0);
5663 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5664 }
5665#ifdef DEBUG
5666 for (int j = 0; j < length; ++j) {
5667 Object* element = elements->get(j);
5668 ASSERT(element == Smi::FromInt(0) ||
5669 (element->IsString() && String::cast(element)->LooksValid()));
5670 }
5671#endif
5672 return i;
5673}
5674
5675
5676// Converts a String to JSArray.
5677// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005678RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005682 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683
5684 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005685 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005686
5687 Handle<FixedArray> elements;
5688 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690 { MaybeObject* maybe_obj =
5691 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5693 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005695
5696 Vector<const char> chars = s->ToAsciiVector();
5697 // Note, this will initialize all elements (not only the prefix)
5698 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5700 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701 *elements,
5702 length);
5703
5704 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005705 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5706 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005707 }
5708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005710 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005711 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5712 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713 }
5714 }
5715
5716#ifdef DEBUG
5717 for (int i = 0; i < length; ++i) {
5718 ASSERT(String::cast(elements->get(i))->length() == 1);
5719 }
5720#endif
5721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723}
5724
5725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005726RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005727 NoHandleAllocation ha;
5728 ASSERT(args.length() == 1);
5729 CONVERT_CHECKED(String, value, args[0]);
5730 return value->ToObject();
5731}
5732
5733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005737 return char_length == 0;
5738}
5739
5740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005741RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 NoHandleAllocation ha;
5743 ASSERT(args.length() == 1);
5744
5745 Object* number = args[0];
5746 RUNTIME_ASSERT(number->IsNumber());
5747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749}
5750
5751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005752RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 1);
5755
5756 Object* number = args[0];
5757 RUNTIME_ASSERT(number->IsNumber());
5758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005760}
5761
5762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005763RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 1);
5766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 CONVERT_DOUBLE_CHECKED(number, args[0]);
5768
5769 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5770 if (number > 0 && number <= Smi::kMaxValue) {
5771 return Smi::FromInt(static_cast<int>(number));
5772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774}
5775
5776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005778 NoHandleAllocation ha;
5779 ASSERT(args.length() == 1);
5780
5781 CONVERT_DOUBLE_CHECKED(number, args[0]);
5782
5783 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5784 if (number > 0 && number <= Smi::kMaxValue) {
5785 return Smi::FromInt(static_cast<int>(number));
5786 }
5787
5788 double double_value = DoubleToInteger(number);
5789 // Map both -0 and +0 to +0.
5790 if (double_value == 0) double_value = 0;
5791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005793}
5794
5795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 NoHandleAllocation ha;
5798 ASSERT(args.length() == 1);
5799
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802}
5803
5804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005805RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
5808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 CONVERT_DOUBLE_CHECKED(number, args[0]);
5810
5811 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5812 if (number > 0 && number <= Smi::kMaxValue) {
5813 return Smi::FromInt(static_cast<int>(number));
5814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816}
5817
5818
ager@chromium.org870a0b62008-11-04 11:43:05 +00005819// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5820// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005821RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005822 NoHandleAllocation ha;
5823 ASSERT(args.length() == 1);
5824
5825 Object* obj = args[0];
5826 if (obj->IsSmi()) {
5827 return obj;
5828 }
5829 if (obj->IsHeapNumber()) {
5830 double value = HeapNumber::cast(obj)->value();
5831 int int_value = FastD2I(value);
5832 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5833 return Smi::FromInt(int_value);
5834 }
5835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005837}
5838
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005840RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005841 NoHandleAllocation ha;
5842 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005844}
5845
5846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005847RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 NoHandleAllocation ha;
5849 ASSERT(args.length() == 2);
5850
5851 CONVERT_DOUBLE_CHECKED(x, args[0]);
5852 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005857RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 NoHandleAllocation ha;
5859 ASSERT(args.length() == 2);
5860
5861 CONVERT_DOUBLE_CHECKED(x, args[0]);
5862 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005863 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864}
5865
5866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005867RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 NoHandleAllocation ha;
5869 ASSERT(args.length() == 2);
5870
5871 CONVERT_DOUBLE_CHECKED(x, args[0]);
5872 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874}
5875
5876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878 NoHandleAllocation ha;
5879 ASSERT(args.length() == 1);
5880
5881 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 0);
5889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005890 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_DOUBLE_CHECKED(x, args[0]);
5899 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 2);
5907
5908 CONVERT_DOUBLE_CHECKED(x, args[0]);
5909 CONVERT_DOUBLE_CHECKED(y, args[1]);
5910
ager@chromium.org3811b432009-10-28 14:53:37 +00005911 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005912 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005913 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 CONVERT_CHECKED(String, str1, args[0]);
5921 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005922 isolate->counters()->string_add_runtime()->Increment();
5923 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005927template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005928static inline void StringBuilderConcatHelper(String* special,
5929 sinkchar* sink,
5930 FixedArray* fixed_array,
5931 int array_length) {
5932 int position = 0;
5933 for (int i = 0; i < array_length; i++) {
5934 Object* element = fixed_array->get(i);
5935 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005937 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005938 int pos;
5939 int len;
5940 if (encoded_slice > 0) {
5941 // Position and length encoded in one smi.
5942 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5943 len = StringBuilderSubstringLength::decode(encoded_slice);
5944 } else {
5945 // Position and length encoded in two smis.
5946 Object* obj = fixed_array->get(++i);
5947 ASSERT(obj->IsSmi());
5948 pos = Smi::cast(obj)->value();
5949 len = -encoded_slice;
5950 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005951 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 sink + position,
5953 pos,
5954 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005955 position += len;
5956 } else {
5957 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 int element_length = string->length();
5959 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005960 position += element_length;
5961 }
5962 }
5963}
5964
5965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005972 return Failure::OutOfMemoryException();
5973 }
5974 int array_length = Smi::cast(args[1])->value();
5975 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005976
5977 // This assumption is used by the slice encoding in one or two smis.
5978 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5979
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005980 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 }
5984 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
5989 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 } else if (array_length == 1) {
5992 Object* first = fixed_array->get(0);
5993 if (first->IsString()) return first;
5994 }
5995
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005996 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 int position = 0;
5998 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005999 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 Object* elt = fixed_array->get(i);
6001 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006002 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006003 int smi_value = Smi::cast(elt)->value();
6004 int pos;
6005 int len;
6006 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006007 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006008 pos = StringBuilderSubstringPosition::decode(smi_value);
6009 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006010 } else {
6011 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006012 len = -smi_value;
6013 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006014 i++;
6015 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006017 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006018 Object* next_smi = fixed_array->get(i);
6019 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006021 }
6022 pos = Smi::cast(next_smi)->value();
6023 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006027 ASSERT(pos >= 0);
6028 ASSERT(len >= 0);
6029 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006031 }
6032 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 } else if (elt->IsString()) {
6034 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006036 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006037 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006043 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006045 return Failure::OutOfMemoryException();
6046 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006047 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 }
6049
6050 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 { MaybeObject* maybe_object =
6055 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 if (!maybe_object->ToObject(&object)) return maybe_object;
6057 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006058 SeqAsciiString* answer = SeqAsciiString::cast(object);
6059 StringBuilderConcatHelper(special,
6060 answer->GetChars(),
6061 fixed_array,
6062 array_length);
6063 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 { MaybeObject* maybe_object =
6066 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006067 if (!maybe_object->ToObject(&object)) return maybe_object;
6068 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006069 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6070 StringBuilderConcatHelper(special,
6071 answer->GetChars(),
6072 fixed_array,
6073 array_length);
6074 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006079RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 3);
6082 CONVERT_CHECKED(JSArray, array, args[0]);
6083 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006084 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006085 return Failure::OutOfMemoryException();
6086 }
6087 int array_length = Smi::cast(args[1])->value();
6088 CONVERT_CHECKED(String, separator, args[2]);
6089
6090 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006092 }
6093 FixedArray* fixed_array = FixedArray::cast(array->elements());
6094 if (fixed_array->length() < array_length) {
6095 array_length = fixed_array->length();
6096 }
6097
6098 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006100 } else if (array_length == 1) {
6101 Object* first = fixed_array->get(0);
6102 if (first->IsString()) return first;
6103 }
6104
6105 int separator_length = separator->length();
6106 int max_nof_separators =
6107 (String::kMaxLength + separator_length - 1) / separator_length;
6108 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006110 return Failure::OutOfMemoryException();
6111 }
6112 int length = (array_length - 1) * separator_length;
6113 for (int i = 0; i < array_length; i++) {
6114 Object* element_obj = fixed_array->get(i);
6115 if (!element_obj->IsString()) {
6116 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 }
6119 String* element = String::cast(element_obj);
6120 int increment = element->length();
6121 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006123 return Failure::OutOfMemoryException();
6124 }
6125 length += increment;
6126 }
6127
6128 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 { MaybeObject* maybe_object =
6130 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006131 if (!maybe_object->ToObject(&object)) return maybe_object;
6132 }
6133 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6134
6135 uc16* sink = answer->GetChars();
6136#ifdef DEBUG
6137 uc16* end = sink + length;
6138#endif
6139
6140 String* first = String::cast(fixed_array->get(0));
6141 int first_length = first->length();
6142 String::WriteToFlat(first, sink, 0, first_length);
6143 sink += first_length;
6144
6145 for (int i = 1; i < array_length; i++) {
6146 ASSERT(sink + separator_length <= end);
6147 String::WriteToFlat(separator, sink, 0, separator_length);
6148 sink += separator_length;
6149
6150 String* element = String::cast(fixed_array->get(i));
6151 int element_length = element->length();
6152 ASSERT(sink + element_length <= end);
6153 String::WriteToFlat(element, sink, 0, element_length);
6154 sink += element_length;
6155 }
6156 ASSERT(sink == end);
6157
6158 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6159 return answer;
6160}
6161
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006162template <typename Char>
6163static void JoinSparseArrayWithSeparator(FixedArray* elements,
6164 int elements_length,
6165 uint32_t array_length,
6166 String* separator,
6167 Vector<Char> buffer) {
6168 int previous_separator_position = 0;
6169 int separator_length = separator->length();
6170 int cursor = 0;
6171 for (int i = 0; i < elements_length; i += 2) {
6172 int position = NumberToInt32(elements->get(i));
6173 String* string = String::cast(elements->get(i + 1));
6174 int string_length = string->length();
6175 if (string->length() > 0) {
6176 while (previous_separator_position < position) {
6177 String::WriteToFlat<Char>(separator, &buffer[cursor],
6178 0, separator_length);
6179 cursor += separator_length;
6180 previous_separator_position++;
6181 }
6182 String::WriteToFlat<Char>(string, &buffer[cursor],
6183 0, string_length);
6184 cursor += string->length();
6185 }
6186 }
6187 if (separator_length > 0) {
6188 // Array length must be representable as a signed 32-bit number,
6189 // otherwise the total string length would have been too large.
6190 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6191 int last_array_index = static_cast<int>(array_length - 1);
6192 while (previous_separator_position < last_array_index) {
6193 String::WriteToFlat<Char>(separator, &buffer[cursor],
6194 0, separator_length);
6195 cursor += separator_length;
6196 previous_separator_position++;
6197 }
6198 }
6199 ASSERT(cursor <= buffer.length());
6200}
6201
6202
6203RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6204 NoHandleAllocation ha;
6205 ASSERT(args.length() == 3);
6206 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6207 RUNTIME_ASSERT(elements_array->HasFastElements());
6208 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6209 CONVERT_CHECKED(String, separator, args[2]);
6210 // elements_array is fast-mode JSarray of alternating positions
6211 // (increasing order) and strings.
6212 // array_length is length of original array (used to add separators);
6213 // separator is string to put between elements. Assumed to be non-empty.
6214
6215 // Find total length of join result.
6216 int string_length = 0;
6217 bool is_ascii = true;
6218 int max_string_length = SeqAsciiString::kMaxLength;
6219 bool overflow = false;
6220 CONVERT_NUMBER_CHECKED(int, elements_length,
6221 Int32, elements_array->length());
6222 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6223 FixedArray* elements = FixedArray::cast(elements_array->elements());
6224 for (int i = 0; i < elements_length; i += 2) {
6225 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6226 CONVERT_CHECKED(String, string, elements->get(i + 1));
6227 int length = string->length();
6228 if (is_ascii && !string->IsAsciiRepresentation()) {
6229 is_ascii = false;
6230 max_string_length = SeqTwoByteString::kMaxLength;
6231 }
6232 if (length > max_string_length ||
6233 max_string_length - length < string_length) {
6234 overflow = true;
6235 break;
6236 }
6237 string_length += length;
6238 }
6239 int separator_length = separator->length();
6240 if (!overflow && separator_length > 0) {
6241 if (array_length <= 0x7fffffffu) {
6242 int separator_count = static_cast<int>(array_length) - 1;
6243 int remaining_length = max_string_length - string_length;
6244 if ((remaining_length / separator_length) >= separator_count) {
6245 string_length += separator_length * (array_length - 1);
6246 } else {
6247 // Not room for the separators within the maximal string length.
6248 overflow = true;
6249 }
6250 } else {
6251 // Nonempty separator and at least 2^31-1 separators necessary
6252 // means that the string is too large to create.
6253 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6254 overflow = true;
6255 }
6256 }
6257 if (overflow) {
6258 // Throw OutOfMemory exception for creating too large a string.
6259 V8::FatalProcessOutOfMemory("Array join result too large.");
6260 }
6261
6262 if (is_ascii) {
6263 MaybeObject* result_allocation =
6264 isolate->heap()->AllocateRawAsciiString(string_length);
6265 if (result_allocation->IsFailure()) return result_allocation;
6266 SeqAsciiString* result_string =
6267 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6268 JoinSparseArrayWithSeparator<char>(elements,
6269 elements_length,
6270 array_length,
6271 separator,
6272 Vector<char>(result_string->GetChars(),
6273 string_length));
6274 return result_string;
6275 } else {
6276 MaybeObject* result_allocation =
6277 isolate->heap()->AllocateRawTwoByteString(string_length);
6278 if (result_allocation->IsFailure()) return result_allocation;
6279 SeqTwoByteString* result_string =
6280 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6281 JoinSparseArrayWithSeparator<uc16>(elements,
6282 elements_length,
6283 array_length,
6284 separator,
6285 Vector<uc16>(result_string->GetChars(),
6286 string_length));
6287 return result_string;
6288 }
6289}
6290
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006292RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 NoHandleAllocation ha;
6294 ASSERT(args.length() == 2);
6295
6296 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6297 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006298 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006299}
6300
6301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006302RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 NoHandleAllocation ha;
6304 ASSERT(args.length() == 2);
6305
6306 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6307 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006308 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006309}
6310
6311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006312RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006323 NoHandleAllocation ha;
6324 ASSERT(args.length() == 1);
6325
6326 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006327 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006328}
6329
6330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006331RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332 NoHandleAllocation ha;
6333 ASSERT(args.length() == 2);
6334
6335 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6336 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006338}
6339
6340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006341RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006342 NoHandleAllocation ha;
6343 ASSERT(args.length() == 2);
6344
6345 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6346 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006347 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348}
6349
6350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006351RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352 NoHandleAllocation ha;
6353 ASSERT(args.length() == 2);
6354
6355 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6356 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006357 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358}
6359
6360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 NoHandleAllocation ha;
6363 ASSERT(args.length() == 2);
6364
6365 CONVERT_DOUBLE_CHECKED(x, args[0]);
6366 CONVERT_DOUBLE_CHECKED(y, args[1]);
6367 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6368 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6369 if (x == y) return Smi::FromInt(EQUAL);
6370 Object* result;
6371 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6372 result = Smi::FromInt(EQUAL);
6373 } else {
6374 result = Smi::FromInt(NOT_EQUAL);
6375 }
6376 return result;
6377}
6378
6379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006380RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381 NoHandleAllocation ha;
6382 ASSERT(args.length() == 2);
6383
6384 CONVERT_CHECKED(String, x, args[0]);
6385 CONVERT_CHECKED(String, y, args[1]);
6386
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006387 bool not_equal = !x->Equals(y);
6388 // This is slightly convoluted because the value that signifies
6389 // equality is 0 and inequality is 1 so we have to negate the result
6390 // from String::Equals.
6391 ASSERT(not_equal == 0 || not_equal == 1);
6392 STATIC_CHECK(EQUAL == 0);
6393 STATIC_CHECK(NOT_EQUAL == 1);
6394 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006395}
6396
6397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006398RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006399 NoHandleAllocation ha;
6400 ASSERT(args.length() == 3);
6401
6402 CONVERT_DOUBLE_CHECKED(x, args[0]);
6403 CONVERT_DOUBLE_CHECKED(y, args[1]);
6404 if (isnan(x) || isnan(y)) return args[2];
6405 if (x == y) return Smi::FromInt(EQUAL);
6406 if (isless(x, y)) return Smi::FromInt(LESS);
6407 return Smi::FromInt(GREATER);
6408}
6409
6410
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006411// Compare two Smis as if they were converted to strings and then
6412// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006413RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006414 NoHandleAllocation ha;
6415 ASSERT(args.length() == 2);
6416
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006417 // Extract the integer values from the Smis.
6418 CONVERT_CHECKED(Smi, x, args[0]);
6419 CONVERT_CHECKED(Smi, y, args[1]);
6420 int x_value = x->value();
6421 int y_value = y->value();
6422
6423 // If the integers are equal so are the string representations.
6424 if (x_value == y_value) return Smi::FromInt(EQUAL);
6425
6426 // If one of the integers are zero the normal integer order is the
6427 // same as the lexicographic order of the string representations.
6428 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6429
ager@chromium.org32912102009-01-16 10:38:43 +00006430 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006431 // smallest because the char code of '-' is less than the char code
6432 // of any digit. Otherwise, we make both values positive.
6433 if (x_value < 0 || y_value < 0) {
6434 if (y_value >= 0) return Smi::FromInt(LESS);
6435 if (x_value >= 0) return Smi::FromInt(GREATER);
6436 x_value = -x_value;
6437 y_value = -y_value;
6438 }
6439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 // Arrays for the individual characters of the two Smis. Smis are
6441 // 31 bit integers and 10 decimal digits are therefore enough.
6442 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6443 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6444 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6445
6446
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006447 // Convert the integers to arrays of their decimal digits.
6448 int x_index = 0;
6449 int y_index = 0;
6450 while (x_value > 0) {
6451 x_elms[x_index++] = x_value % 10;
6452 x_value /= 10;
6453 }
6454 while (y_value > 0) {
6455 y_elms[y_index++] = y_value % 10;
6456 y_value /= 10;
6457 }
6458
6459 // Loop through the arrays of decimal digits finding the first place
6460 // where they differ.
6461 while (--x_index >= 0 && --y_index >= 0) {
6462 int diff = x_elms[x_index] - y_elms[y_index];
6463 if (diff != 0) return Smi::FromInt(diff);
6464 }
6465
6466 // If one array is a suffix of the other array, the longest array is
6467 // the representation of the largest of the Smis in the
6468 // lexicographic ordering.
6469 return Smi::FromInt(x_index - y_index);
6470}
6471
6472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473static Object* StringInputBufferCompare(RuntimeState* state,
6474 String* x,
6475 String* y) {
6476 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6477 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006478 bufx.Reset(x);
6479 bufy.Reset(y);
6480 while (bufx.has_more() && bufy.has_more()) {
6481 int d = bufx.GetNext() - bufy.GetNext();
6482 if (d < 0) return Smi::FromInt(LESS);
6483 else if (d > 0) return Smi::FromInt(GREATER);
6484 }
6485
6486 // x is (non-trivial) prefix of y:
6487 if (bufy.has_more()) return Smi::FromInt(LESS);
6488 // y is prefix of x:
6489 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6490}
6491
6492
6493static Object* FlatStringCompare(String* x, String* y) {
6494 ASSERT(x->IsFlat());
6495 ASSERT(y->IsFlat());
6496 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6497 int prefix_length = x->length();
6498 if (y->length() < prefix_length) {
6499 prefix_length = y->length();
6500 equal_prefix_result = Smi::FromInt(GREATER);
6501 } else if (y->length() > prefix_length) {
6502 equal_prefix_result = Smi::FromInt(LESS);
6503 }
6504 int r;
6505 if (x->IsAsciiRepresentation()) {
6506 Vector<const char> x_chars = x->ToAsciiVector();
6507 if (y->IsAsciiRepresentation()) {
6508 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006509 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006510 } else {
6511 Vector<const uc16> y_chars = y->ToUC16Vector();
6512 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6513 }
6514 } else {
6515 Vector<const uc16> x_chars = x->ToUC16Vector();
6516 if (y->IsAsciiRepresentation()) {
6517 Vector<const char> y_chars = y->ToAsciiVector();
6518 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6519 } else {
6520 Vector<const uc16> y_chars = y->ToUC16Vector();
6521 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6522 }
6523 }
6524 Object* result;
6525 if (r == 0) {
6526 result = equal_prefix_result;
6527 } else {
6528 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 ASSERT(result ==
6531 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006532 return result;
6533}
6534
6535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 2);
6539
6540 CONVERT_CHECKED(String, x, args[0]);
6541 CONVERT_CHECKED(String, y, args[1]);
6542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006544
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 // A few fast case tests before we flatten.
6546 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006547 if (y->length() == 0) {
6548 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006550 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551 return Smi::FromInt(LESS);
6552 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006553
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006554 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006555 if (d < 0) return Smi::FromInt(LESS);
6556 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557
lrn@chromium.org303ada72010-10-27 09:33:13 +00006558 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006560 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006563 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006566 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568}
6569
6570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006571RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 NoHandleAllocation ha;
6573 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575
6576 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578}
6579
6580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585
6586 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588}
6589
6590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595
6596 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598}
6599
6600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601static const double kPiDividedBy4 = 0.78539816339744830962;
6602
6603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006604RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605 NoHandleAllocation ha;
6606 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608
6609 CONVERT_DOUBLE_CHECKED(x, args[0]);
6610 CONVERT_DOUBLE_CHECKED(y, args[1]);
6611 double result;
6612 if (isinf(x) && isinf(y)) {
6613 // Make sure that the result in case of two infinite arguments
6614 // is a multiple of Pi / 4. The sign of the result is determined
6615 // by the first argument (x) and the sign of the second argument
6616 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 int multiplier = (x < 0) ? -1 : 1;
6618 if (y < 0) multiplier *= 3;
6619 result = multiplier * kPiDividedBy4;
6620 } else {
6621 result = atan2(x, y);
6622 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624}
6625
6626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006627RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 NoHandleAllocation ha;
6629 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631
6632 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641
6642 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006643 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644}
6645
6646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006647RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648 NoHandleAllocation ha;
6649 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006650 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651
6652 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006653 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654}
6655
6656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006657RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006658 NoHandleAllocation ha;
6659 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006660 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661
6662 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006663 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664}
6665
6666
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006667RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 NoHandleAllocation ha;
6669 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671
6672 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006673 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674}
6675
6676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006677RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 NoHandleAllocation ha;
6679 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681
6682 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006683
6684 // If the second argument is a smi, it is much faster to call the
6685 // custom powi() function than the generic pow().
6686 if (args[1]->IsSmi()) {
6687 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006689 }
6690
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693}
6694
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006695// Fast version of Math.pow if we know that y is not an integer and
6696// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006697RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006698 NoHandleAllocation ha;
6699 ASSERT(args.length() == 2);
6700 CONVERT_DOUBLE_CHECKED(x, args[0]);
6701 CONVERT_DOUBLE_CHECKED(y, args[1]);
6702 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006703 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006704 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006706 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006708 }
6709}
6710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006712RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 NoHandleAllocation ha;
6714 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006715 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006717 if (!args[0]->IsHeapNumber()) {
6718 // Must be smi. Return the argument unchanged for all the other types
6719 // to make fuzz-natives test happy.
6720 return args[0];
6721 }
6722
6723 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6724
6725 double value = number->value();
6726 int exponent = number->get_exponent();
6727 int sign = number->get_sign();
6728
danno@chromium.org160a7b02011-04-18 15:51:38 +00006729 if (exponent < -1) {
6730 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6731 if (sign) return isolate->heap()->minus_zero_value();
6732 return Smi::FromInt(0);
6733 }
6734
6735 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6736 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6737 // agument holds for 32-bit smis).
6738 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006739 return Smi::FromInt(static_cast<int>(value + 0.5));
6740 }
6741
6742 // If the magnitude is big enough, there's no place for fraction part. If we
6743 // try to add 0.5 to this number, 1.0 will be added instead.
6744 if (exponent >= 52) {
6745 return number;
6746 }
6747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006748 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006749
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006750 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752}
6753
6754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006755RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 NoHandleAllocation ha;
6757 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006758 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759
6760 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762}
6763
6764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006765RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 NoHandleAllocation ha;
6767 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006768 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769
6770 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772}
6773
6774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006775RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 NoHandleAllocation ha;
6777 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779
6780 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782}
6783
6784
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006785static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006786 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6787 181, 212, 243, 273, 304, 334};
6788 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6789 182, 213, 244, 274, 305, 335};
6790
6791 year += month / 12;
6792 month %= 12;
6793 if (month < 0) {
6794 year--;
6795 month += 12;
6796 }
6797
6798 ASSERT(month >= 0);
6799 ASSERT(month < 12);
6800
6801 // year_delta is an arbitrary number such that:
6802 // a) year_delta = -1 (mod 400)
6803 // b) year + year_delta > 0 for years in the range defined by
6804 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6805 // Jan 1 1970. This is required so that we don't run into integer
6806 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006807 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006808 // operations.
6809 static const int year_delta = 399999;
6810 static const int base_day = 365 * (1970 + year_delta) +
6811 (1970 + year_delta) / 4 -
6812 (1970 + year_delta) / 100 +
6813 (1970 + year_delta) / 400;
6814
6815 int year1 = year + year_delta;
6816 int day_from_year = 365 * year1 +
6817 year1 / 4 -
6818 year1 / 100 +
6819 year1 / 400 -
6820 base_day;
6821
6822 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006823 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006824 }
6825
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006826 return day_from_year + day_from_month_leap[month] + day - 1;
6827}
6828
6829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006830RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006831 NoHandleAllocation ha;
6832 ASSERT(args.length() == 3);
6833
6834 CONVERT_SMI_CHECKED(year, args[0]);
6835 CONVERT_SMI_CHECKED(month, args[1]);
6836 CONVERT_SMI_CHECKED(date, args[2]);
6837
6838 return Smi::FromInt(MakeDay(year, month, date));
6839}
6840
6841
6842static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6843static const int kDaysIn4Years = 4 * 365 + 1;
6844static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6845static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6846static const int kDays1970to2000 = 30 * 365 + 7;
6847static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6848 kDays1970to2000;
6849static const int kYearsOffset = 400000;
6850
6851static const char kDayInYear[] = {
6852 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6853 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6854 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6855 22, 23, 24, 25, 26, 27, 28,
6856 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6857 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6858 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6859 22, 23, 24, 25, 26, 27, 28, 29, 30,
6860 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6861 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6862 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6863 22, 23, 24, 25, 26, 27, 28, 29, 30,
6864 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6865 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6866 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6867 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6868 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6869 22, 23, 24, 25, 26, 27, 28, 29, 30,
6870 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6871 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6872 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6873 22, 23, 24, 25, 26, 27, 28, 29, 30,
6874 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6875 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6876
6877 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6878 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6879 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6880 22, 23, 24, 25, 26, 27, 28,
6881 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6882 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6883 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6884 22, 23, 24, 25, 26, 27, 28, 29, 30,
6885 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6886 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6887 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6888 22, 23, 24, 25, 26, 27, 28, 29, 30,
6889 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6890 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6891 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6892 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6893 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6894 22, 23, 24, 25, 26, 27, 28, 29, 30,
6895 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6896 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6897 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6898 22, 23, 24, 25, 26, 27, 28, 29, 30,
6899 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6900 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6901
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, 31,
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,
6906 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6907 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6908 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6909 22, 23, 24, 25, 26, 27, 28, 29, 30,
6910 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6911 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6912 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6913 22, 23, 24, 25, 26, 27, 28, 29, 30,
6914 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6915 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6916 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6917 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6918 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6919 22, 23, 24, 25, 26, 27, 28, 29, 30,
6920 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6921 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6922 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6923 22, 23, 24, 25, 26, 27, 28, 29, 30,
6924 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6925 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6926
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, 31,
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,
6931 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6932 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6933 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6934 22, 23, 24, 25, 26, 27, 28, 29, 30,
6935 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6936 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6937 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6938 22, 23, 24, 25, 26, 27, 28, 29, 30,
6939 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6940 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6941 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6942 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6943 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6944 22, 23, 24, 25, 26, 27, 28, 29, 30,
6945 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6946 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6947 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6948 22, 23, 24, 25, 26, 27, 28, 29, 30,
6949 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6950 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6951
6952static const char kMonthInYear[] = {
6953 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,
6954 0, 0, 0, 0, 0, 0,
6955 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,
6956 1, 1, 1,
6957 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,
6958 2, 2, 2, 2, 2, 2,
6959 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,
6960 3, 3, 3, 3, 3,
6961 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,
6962 4, 4, 4, 4, 4, 4,
6963 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,
6964 5, 5, 5, 5, 5,
6965 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,
6966 6, 6, 6, 6, 6, 6,
6967 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,
6968 7, 7, 7, 7, 7, 7,
6969 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,
6970 8, 8, 8, 8, 8,
6971 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,
6972 9, 9, 9, 9, 9, 9,
6973 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6974 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6975 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6976 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6977
6978 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,
6979 0, 0, 0, 0, 0, 0,
6980 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,
6981 1, 1, 1,
6982 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,
6983 2, 2, 2, 2, 2, 2,
6984 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,
6985 3, 3, 3, 3, 3,
6986 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,
6987 4, 4, 4, 4, 4, 4,
6988 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,
6989 5, 5, 5, 5, 5,
6990 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,
6991 6, 6, 6, 6, 6, 6,
6992 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,
6993 7, 7, 7, 7, 7, 7,
6994 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,
6995 8, 8, 8, 8, 8,
6996 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,
6997 9, 9, 9, 9, 9, 9,
6998 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6999 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7000 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7001 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7002
7003 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,
7004 0, 0, 0, 0, 0, 0,
7005 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,
7006 1, 1, 1, 1,
7007 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,
7008 2, 2, 2, 2, 2, 2,
7009 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,
7010 3, 3, 3, 3, 3,
7011 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,
7012 4, 4, 4, 4, 4, 4,
7013 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,
7014 5, 5, 5, 5, 5,
7015 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,
7016 6, 6, 6, 6, 6, 6,
7017 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,
7018 7, 7, 7, 7, 7, 7,
7019 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,
7020 8, 8, 8, 8, 8,
7021 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,
7022 9, 9, 9, 9, 9, 9,
7023 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7024 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7025 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7026 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7027
7028 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,
7029 0, 0, 0, 0, 0, 0,
7030 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,
7031 1, 1, 1,
7032 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,
7033 2, 2, 2, 2, 2, 2,
7034 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,
7035 3, 3, 3, 3, 3,
7036 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,
7037 4, 4, 4, 4, 4, 4,
7038 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,
7039 5, 5, 5, 5, 5,
7040 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,
7041 6, 6, 6, 6, 6, 6,
7042 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,
7043 7, 7, 7, 7, 7, 7,
7044 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,
7045 8, 8, 8, 8, 8,
7046 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,
7047 9, 9, 9, 9, 9, 9,
7048 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7049 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7050 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7051 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7052
7053
7054// This function works for dates from 1970 to 2099.
7055static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007056 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007057#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007058 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007059#endif
7060
7061 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7062 date %= kDaysIn4Years;
7063
7064 month = kMonthInYear[date];
7065 day = kDayInYear[date];
7066
7067 ASSERT(MakeDay(year, month, day) == save_date);
7068}
7069
7070
7071static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007072 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007073#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007074 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007075#endif
7076
7077 date += kDaysOffset;
7078 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7079 date %= kDaysIn400Years;
7080
7081 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7082
7083 date--;
7084 int yd1 = date / kDaysIn100Years;
7085 date %= kDaysIn100Years;
7086 year += 100 * yd1;
7087
7088 date++;
7089 int yd2 = date / kDaysIn4Years;
7090 date %= kDaysIn4Years;
7091 year += 4 * yd2;
7092
7093 date--;
7094 int yd3 = date / 365;
7095 date %= 365;
7096 year += yd3;
7097
7098 bool is_leap = (!yd1 || yd2) && !yd3;
7099
7100 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007101 ASSERT(is_leap || (date >= 0));
7102 ASSERT((date < 365) || (is_leap && (date < 366)));
7103 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7104 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7105 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007106
7107 if (is_leap) {
7108 day = kDayInYear[2*365 + 1 + date];
7109 month = kMonthInYear[2*365 + 1 + date];
7110 } else {
7111 day = kDayInYear[date];
7112 month = kMonthInYear[date];
7113 }
7114
7115 ASSERT(MakeDay(year, month, day) == save_date);
7116}
7117
7118
7119static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007120 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007121 if (date >= 0 && date < 32 * kDaysIn4Years) {
7122 DateYMDFromTimeAfter1970(date, year, month, day);
7123 } else {
7124 DateYMDFromTimeSlow(date, year, month, day);
7125 }
7126}
7127
7128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007129RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 2);
7132
7133 CONVERT_DOUBLE_CHECKED(t, args[0]);
7134 CONVERT_CHECKED(JSArray, res_array, args[1]);
7135
7136 int year, month, day;
7137 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007139 RUNTIME_ASSERT(res_array->elements()->map() ==
7140 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007141 FixedArray* elms = FixedArray::cast(res_array->elements());
7142 RUNTIME_ASSERT(elms->length() == 3);
7143
7144 elms->set(0, Smi::FromInt(year));
7145 elms->set(1, Smi::FromInt(month));
7146 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007148 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007149}
7150
7151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007152RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007153 NoHandleAllocation ha;
7154 ASSERT(args.length() == 3);
7155
7156 JSFunction* callee = JSFunction::cast(args[0]);
7157 Object** parameters = reinterpret_cast<Object**>(args[1]);
7158 const int length = Smi::cast(args[2])->value();
7159
lrn@chromium.org303ada72010-10-27 09:33:13 +00007160 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007161 { MaybeObject* maybe_result =
7162 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007163 if (!maybe_result->ToObject(&result)) return maybe_result;
7164 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007165 // Allocate the elements if needed.
7166 if (length > 0) {
7167 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007168 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007169 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007170 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007172
7173 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007174 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007176 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007177
7178 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007179 for (int i = 0; i < length; i++) {
7180 array->set(i, *--parameters, mode);
7181 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007182 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007183 }
7184 return result;
7185}
7186
7187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007188RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007189 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007190 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007191 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007192 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007193 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007195 // Allocate global closures in old space and allocate local closures
7196 // in new space. Additionally pretenure closures that are assigned
7197 // directly to properties.
7198 pretenure = pretenure || (context->global_context() == *context);
7199 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007200 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7202 context,
7203 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007204 return *result;
7205}
7206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007207
7208static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7209 int* total_argc) {
7210 // Find frame containing arguments passed to the caller.
7211 JavaScriptFrameIterator it;
7212 JavaScriptFrame* frame = it.frame();
7213 List<JSFunction*> functions(2);
7214 frame->GetFunctions(&functions);
7215 if (functions.length() > 1) {
7216 int inlined_frame_index = functions.length() - 1;
7217 JSFunction* inlined_function = functions[inlined_frame_index];
7218 int args_count = inlined_function->shared()->formal_parameter_count();
7219 ScopedVector<SlotRef> args_slots(args_count);
7220 SlotRef::ComputeSlotMappingForArguments(frame,
7221 inlined_frame_index,
7222 &args_slots);
7223
7224 *total_argc = bound_argc + args_count;
7225 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7226 for (int i = 0; i < args_count; i++) {
7227 Handle<Object> val = args_slots[i].GetValue();
7228 param_data[bound_argc + i] = val.location();
7229 }
7230 return param_data;
7231 } else {
7232 it.AdvanceToArgumentsFrame();
7233 frame = it.frame();
7234 int args_count = frame->ComputeParametersCount();
7235
7236 *total_argc = bound_argc + args_count;
7237 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7238 for (int i = 0; i < args_count; i++) {
7239 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7240 param_data[bound_argc + i] = val.location();
7241 }
7242 return param_data;
7243 }
7244}
7245
7246
7247RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007249 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007250 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007251 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007252
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007253 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007254 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007255 int bound_argc = 0;
7256 if (!args[1]->IsNull()) {
7257 CONVERT_ARG_CHECKED(JSArray, params, 1);
7258 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007259 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007260 bound_argc = Smi::cast(params->length())->value();
7261 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007263 int total_argc = 0;
7264 SmartPointer<Object**> param_data =
7265 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007266 for (int i = 0; i < bound_argc; i++) {
7267 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007268 param_data[i] = val.location();
7269 }
7270
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007271 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007272 Handle<Object> result =
7273 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007274 if (exception) {
7275 return Failure::Exception();
7276 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007277
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007278 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007279 return *result;
7280}
7281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007282
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007283static void TrySettingInlineConstructStub(Isolate* isolate,
7284 Handle<JSFunction> function) {
7285 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007286 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007287 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007288 }
7289 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007290 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007291 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007292 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007293 function->shared()->set_construct_stub(
7294 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007295 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007296 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007297}
7298
7299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007300RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302 ASSERT(args.length() == 1);
7303
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007304 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007305
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007306 // If the constructor isn't a proper function we throw a type error.
7307 if (!constructor->IsJSFunction()) {
7308 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7309 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 isolate->factory()->NewTypeError("not_constructor", arguments);
7311 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007312 }
7313
7314 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007315
7316 // If function should not have prototype, construction is not allowed. In this
7317 // case generated code bailouts here, since function has no initial_map.
7318 if (!function->should_have_prototype()) {
7319 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7320 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007321 isolate->factory()->NewTypeError("not_constructor", arguments);
7322 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007323 }
7324
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007325#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007327 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 if (debug->StepInActive()) {
7329 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007330 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007331#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007333 if (function->has_initial_map()) {
7334 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335 // The 'Function' function ignores the receiver object when
7336 // called using 'new' and creates a new JSFunction object that
7337 // is returned. The receiver object is only used for error
7338 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007340 // allocate JSFunctions since it does not properly initialize
7341 // the shared part of the function. Since the receiver is
7342 // ignored anyway, we use the global object as the receiver
7343 // instead of a new JSFunction object. This way, errors are
7344 // reported the same way whether or not 'Function' is called
7345 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 }
7349
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007350 // The function should be compiled for the optimization hints to be
7351 // available. We cannot use EnsureCompiled because that forces a
7352 // compilation through the shared function info which makes it
7353 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007355 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007356
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007357 if (!function->has_initial_map() &&
7358 shared->IsInobjectSlackTrackingInProgress()) {
7359 // The tracking is already in progress for another function. We can only
7360 // track one initial_map at a time, so we force the completion before the
7361 // function is called as a constructor for the first time.
7362 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007363 }
7364
7365 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7367 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007368 // Delay setting the stub if inobject slack tracking is in progress.
7369 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007371 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->constructed_objects()->Increment();
7374 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007375
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007376 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007382 ASSERT(args.length() == 1);
7383
7384 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7385 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007389}
7390
7391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007392RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 ASSERT(args.length() == 1);
7395
7396 Handle<JSFunction> function = args.at<JSFunction>(0);
7397#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007398 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007400 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401 PrintF("]\n");
7402 }
7403#endif
7404
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007405 // Compile the target function. Here we compile using CompileLazyInLoop in
7406 // order to get the optimized version. This helps code like delta-blue
7407 // that calls performance-critical routines through constructors. A
7408 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7409 // direct call. Since the in-loop tracking takes place through CallICs
7410 // this means that things called through constructors are never known to
7411 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007413 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 return Failure::Exception();
7415 }
7416
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007417 // All done. Return the compiled code.
7418 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419 return function->code();
7420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007425 ASSERT(args.length() == 1);
7426 Handle<JSFunction> function = args.at<JSFunction>(0);
7427 // If the function is not optimizable or debugger is active continue using the
7428 // code from the full compiler.
7429 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007430 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007431 if (FLAG_trace_opt) {
7432 PrintF("[failed to optimize ");
7433 function->PrintName();
7434 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7435 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007436 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007437 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007438 function->ReplaceCode(function->shared()->code());
7439 return function->code();
7440 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007441 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007442 return function->code();
7443 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007444 if (FLAG_trace_opt) {
7445 PrintF("[failed to optimize ");
7446 function->PrintName();
7447 PrintF(": optimized compilation failed]\n");
7448 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007449 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007450 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007451}
7452
7453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007454RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007455 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007456 ASSERT(args.length() == 1);
7457 RUNTIME_ASSERT(args[0]->IsSmi());
7458 Deoptimizer::BailoutType type =
7459 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007460 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7461 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462 int frames = deoptimizer->output_count();
7463
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007464 deoptimizer->MaterializeHeapNumbers();
7465 delete deoptimizer;
7466
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007467 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007468 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007469 for (int i = 0; i < frames - 1; i++) it.Advance();
7470 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007471
7472 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007474 Handle<Object> arguments;
7475 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007476 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007477 if (arguments.is_null()) {
7478 // FunctionGetArguments can't throw an exception, so cast away the
7479 // doubt with an assert.
7480 arguments = Handle<Object>(
7481 Accessors::FunctionGetArguments(*function,
7482 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007483 ASSERT(*arguments != isolate->heap()->null_value());
7484 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007485 }
7486 frame->SetExpression(i, *arguments);
7487 }
7488 }
7489
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007490 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007491 if (type == Deoptimizer::EAGER) {
7492 RUNTIME_ASSERT(function->IsOptimized());
7493 } else {
7494 RUNTIME_ASSERT(!function->IsOptimized());
7495 }
7496
7497 // Avoid doing too much work when running with --always-opt and keep
7498 // the optimized code around.
7499 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007500 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007501 }
7502
7503 // Count the number of optimized activations of the function.
7504 int activations = 0;
7505 while (!it.done()) {
7506 JavaScriptFrame* frame = it.frame();
7507 if (frame->is_optimized() && frame->function() == *function) {
7508 activations++;
7509 }
7510 it.Advance();
7511 }
7512
7513 // TODO(kasperl): For now, we cannot support removing the optimized
7514 // code when we have recursive invocations of the same function.
7515 if (activations == 0) {
7516 if (FLAG_trace_deopt) {
7517 PrintF("[removing optimized code for: ");
7518 function->PrintName();
7519 PrintF("]\n");
7520 }
7521 function->ReplaceCode(function->shared()->code());
7522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007523 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007524}
7525
7526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007527RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007529 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007530 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007531}
7532
7533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007534RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007535 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007536 ASSERT(args.length() == 1);
7537 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007539
7540 Deoptimizer::DeoptimizeFunction(*function);
7541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007543}
7544
7545
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007546RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7547 HandleScope scope(isolate);
7548 ASSERT(args.length() == 1);
7549 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7550 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7551 function->MarkForLazyRecompilation();
7552 return isolate->heap()->undefined_value();
7553}
7554
7555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007558 ASSERT(args.length() == 1);
7559 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7560
7561 // We're not prepared to handle a function with arguments object.
7562 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7563
7564 // We have hit a back edge in an unoptimized frame for a function that was
7565 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007566 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007567 // Keep track of whether we've succeeded in optimizing.
7568 bool succeeded = unoptimized->optimizable();
7569 if (succeeded) {
7570 // If we are trying to do OSR when there are already optimized
7571 // activations of the function, it means (a) the function is directly or
7572 // indirectly recursive and (b) an optimized invocation has been
7573 // deoptimized so that we are currently in an unoptimized activation.
7574 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007575 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007576 while (succeeded && !it.done()) {
7577 JavaScriptFrame* frame = it.frame();
7578 succeeded = !frame->is_optimized() || frame->function() != *function;
7579 it.Advance();
7580 }
7581 }
7582
7583 int ast_id = AstNode::kNoNumber;
7584 if (succeeded) {
7585 // The top JS function is this one, the PC is somewhere in the
7586 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007587 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007588 JavaScriptFrame* frame = it.frame();
7589 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007590 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007591 ASSERT(unoptimized->contains(frame->pc()));
7592
7593 // Use linear search of the unoptimized code's stack check table to find
7594 // the AST id matching the PC.
7595 Address start = unoptimized->instruction_start();
7596 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007597 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007598 uint32_t table_length = Memory::uint32_at(table_cursor);
7599 table_cursor += kIntSize;
7600 for (unsigned i = 0; i < table_length; ++i) {
7601 // Table entries are (AST id, pc offset) pairs.
7602 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7603 if (pc_offset == target_pc_offset) {
7604 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7605 break;
7606 }
7607 table_cursor += 2 * kIntSize;
7608 }
7609 ASSERT(ast_id != AstNode::kNoNumber);
7610 if (FLAG_trace_osr) {
7611 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7612 function->PrintName();
7613 PrintF("]\n");
7614 }
7615
7616 // Try to compile the optimized code. A true return value from
7617 // CompileOptimized means that compilation succeeded, not necessarily
7618 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007619 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7620 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007621 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7622 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007623 if (data->OsrPcOffset()->value() >= 0) {
7624 if (FLAG_trace_osr) {
7625 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007626 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007627 }
7628 ASSERT(data->OsrAstId()->value() == ast_id);
7629 } else {
7630 // We may never generate the desired OSR entry if we emit an
7631 // early deoptimize.
7632 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007633 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007634 } else {
7635 succeeded = false;
7636 }
7637 }
7638
7639 // Revert to the original stack checks in the original unoptimized code.
7640 if (FLAG_trace_osr) {
7641 PrintF("[restoring original stack checks in ");
7642 function->PrintName();
7643 PrintF("]\n");
7644 }
7645 StackCheckStub check_stub;
7646 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007647 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007648 Deoptimizer::RevertStackCheckCode(*unoptimized,
7649 *check_code,
7650 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007651
7652 // Allow OSR only at nesting level zero again.
7653 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7654
7655 // If the optimization attempt succeeded, return the AST id tagged as a
7656 // smi. This tells the builtin that we need to translate the unoptimized
7657 // frame to an optimized one.
7658 if (succeeded) {
7659 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7660 return Smi::FromInt(ast_id);
7661 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007662 if (function->IsMarkedForLazyRecompilation()) {
7663 function->ReplaceCode(function->shared()->code());
7664 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007665 return Smi::FromInt(-1);
7666 }
7667}
7668
7669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007670RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007671 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007672 ASSERT(args.length() == 1);
7673 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7674 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7675}
7676
7677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007678RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007679 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007680 ASSERT(args.length() == 1);
7681 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7682 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7683}
7684
7685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007686RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007687 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007688 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007689
kasper.lund7276f142008-07-30 08:49:36 +00007690 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007691 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007692 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007693 { MaybeObject* maybe_result =
7694 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007695 if (!maybe_result->ToObject(&result)) return maybe_result;
7696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699
kasper.lund7276f142008-07-30 08:49:36 +00007700 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007701}
7702
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007704MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7705 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007706 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007708 Object* js_object = object;
7709 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007710 MaybeObject* maybe_js_object = js_object->ToObject();
7711 if (!maybe_js_object->ToObject(&js_object)) {
7712 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7713 return maybe_js_object;
7714 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 HandleScope scope(isolate);
7716 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007717 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718 isolate->factory()->NewTypeError("with_expression",
7719 HandleVector(&handle, 1));
7720 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721 }
7722 }
7723
lrn@chromium.org303ada72010-10-27 09:33:13 +00007724 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7726 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007727 if (!maybe_result->ToObject(&result)) return maybe_result;
7728 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007730 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007731 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732
kasper.lund7276f142008-07-30 08:49:36 +00007733 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007734}
7735
7736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007737RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007738 NoHandleAllocation ha;
7739 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007740 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007741}
7742
7743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007744RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007745 NoHandleAllocation ha;
7746 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007748}
7749
7750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007751RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007753 ASSERT(args.length() == 2);
7754
7755 CONVERT_ARG_CHECKED(Context, context, 0);
7756 CONVERT_ARG_CHECKED(String, name, 1);
7757
7758 int index;
7759 PropertyAttributes attributes;
7760 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007761 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007762
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007763 // If the slot was not found the result is true.
7764 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007765 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 }
7767
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007768 // If the slot was found in a context, it should be DONT_DELETE.
7769 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007770 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007771 }
7772
7773 // The slot was found in a JSObject, either a context extension object,
7774 // the global object, or an arguments object. Try to delete it
7775 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7776 // which allows deleting all parameters in functions that mention
7777 // 'arguments', we do this even for the case of slots found on an
7778 // arguments object. The slot was found on an arguments object if the
7779 // index is non-negative.
7780 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7781 if (index >= 0) {
7782 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7783 } else {
7784 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786}
7787
7788
ager@chromium.orga1645e22009-09-09 19:27:10 +00007789// A mechanism to return a pair of Object pointers in registers (if possible).
7790// How this is achieved is calling convention-dependent.
7791// All currently supported x86 compiles uses calling conventions that are cdecl
7792// variants where a 64-bit value is returned in two 32-bit registers
7793// (edx:eax on ia32, r1:r0 on ARM).
7794// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7795// In Win64 calling convention, a struct of two pointers is returned in memory,
7796// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007797#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007798struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007799 MaybeObject* x;
7800 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007801};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007802
lrn@chromium.org303ada72010-10-27 09:33:13 +00007803static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007804 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007805 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7806 // In Win64 they are assigned to a hidden first argument.
7807 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007808}
7809#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007810typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007811static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007813 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007815#endif
7816
7817
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007818static inline MaybeObject* Unhole(Heap* heap,
7819 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007820 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7822 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007823 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824}
7825
7826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007827static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7828 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007829 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007830 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007831 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007832 JSFunction* context_extension_function =
7833 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007834 // If the holder isn't a context extension object, we just return it
7835 // as the receiver. This allows arguments objects to be used as
7836 // receivers, but only if they are put in the context scope chain
7837 // explicitly via a with-statement.
7838 Object* constructor = holder->map()->constructor();
7839 if (constructor != context_extension_function) return holder;
7840 // Fall back to using the global object as the receiver if the
7841 // property turns out to be a local variable allocated in a context
7842 // extension object - introduced via eval.
7843 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007844}
7845
7846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847static ObjectPair LoadContextSlotHelper(Arguments args,
7848 Isolate* isolate,
7849 bool throw_error) {
7850 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007851 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007852
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007853 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007854 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007855 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007856 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007857 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858
7859 int index;
7860 PropertyAttributes attributes;
7861 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007862 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007863
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007864 // If the index is non-negative, the slot has been found in a local
7865 // variable or a parameter. Read it from the context object or the
7866 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007867 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007868 // If the "property" we were looking for is a local variable or an
7869 // argument in a context, the receiver is the global object; see
7870 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 JSObject* receiver =
7872 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007873 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007874 ? Context::cast(*holder)->get(index)
7875 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007877 }
7878
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007879 // If the holder is found, we read the property from it.
7880 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007881 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007882 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007883 JSObject* receiver;
7884 if (object->IsGlobalObject()) {
7885 receiver = GlobalObject::cast(object)->global_receiver();
7886 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007888 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007889 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007890 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007891 // No need to unhole the value here. This is taken care of by the
7892 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007893 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007894 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007895 }
7896
7897 if (throw_error) {
7898 // The property doesn't exist - throw exception.
7899 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 isolate->factory()->NewReferenceError("not_defined",
7901 HandleVector(&name, 1));
7902 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007903 } else {
7904 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007905 return MakePair(isolate->heap()->undefined_value(),
7906 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907 }
7908}
7909
7910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913}
7914
7915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007916RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007918}
7919
7920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007921RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007922 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007923 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007927 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007928 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7929 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7930 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007931 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932
7933 int index;
7934 PropertyAttributes attributes;
7935 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007936 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937
7938 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007939 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007940 // Ignore if read_only variable.
7941 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007942 // Context is a fixed array and set cannot fail.
7943 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007944 } else if (strict_mode == kStrictMode) {
7945 // Setting read only property in strict mode.
7946 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 isolate->factory()->NewTypeError("strict_cannot_assign",
7948 HandleVector(&name, 1));
7949 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007950 }
7951 } else {
7952 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007953 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007954 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007955 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007956 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007957 return Failure::Exception();
7958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007959 }
7960 return *value;
7961 }
7962
7963 // Slow case: The property is not in a FixedArray context.
7964 // It is either in an JSObject extension context or it was not found.
7965 Handle<JSObject> context_ext;
7966
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007967 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007968 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007969 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007970 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007971 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007972 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007973
7974 if (strict_mode == kStrictMode) {
7975 // Throw in strict mode (assignment to undefined variable).
7976 Handle<Object> error =
7977 isolate->factory()->NewReferenceError(
7978 "not_defined", HandleVector(&name, 1));
7979 return isolate->Throw(*error);
7980 }
7981 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007982 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007983 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984 }
7985
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007986 // Set the property, but ignore if read_only variable on the context
7987 // extension object itself.
7988 if ((attributes & READ_ONLY) == 0 ||
7989 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007990 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007992 SetProperty(context_ext, name, value, NONE, strict_mode));
7993 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007994 // Setting read only property in strict mode.
7995 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007996 isolate->factory()->NewTypeError(
7997 "strict_cannot_assign", HandleVector(&name, 1));
7998 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007999 }
8000 return *value;
8001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006 ASSERT(args.length() == 1);
8007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008008 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008009}
8010
8011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008012RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008014 ASSERT(args.length() == 1);
8015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008016 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017}
8018
8019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008020RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008021 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008023}
8024
8025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008026RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008028 ASSERT(args.length() == 1);
8029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008032 isolate->factory()->NewReferenceError("not_defined",
8033 HandleVector(&name, 1));
8034 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035}
8036
8037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008038RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008039 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040
8041 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 if (isolate->stack_guard()->IsStackOverflow()) {
8043 NoHandleAllocation na;
8044 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008047 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048}
8049
8050
8051// NOTE: These PrintXXX functions are defined for all builds (not just
8052// DEBUG builds) because we may want to be able to trace function
8053// calls in all modes.
8054static void PrintString(String* str) {
8055 // not uncommon to have empty strings
8056 if (str->length() > 0) {
8057 SmartPointer<char> s =
8058 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8059 PrintF("%s", *s);
8060 }
8061}
8062
8063
8064static void PrintObject(Object* obj) {
8065 if (obj->IsSmi()) {
8066 PrintF("%d", Smi::cast(obj)->value());
8067 } else if (obj->IsString() || obj->IsSymbol()) {
8068 PrintString(String::cast(obj));
8069 } else if (obj->IsNumber()) {
8070 PrintF("%g", obj->Number());
8071 } else if (obj->IsFailure()) {
8072 PrintF("<failure>");
8073 } else if (obj->IsUndefined()) {
8074 PrintF("<undefined>");
8075 } else if (obj->IsNull()) {
8076 PrintF("<null>");
8077 } else if (obj->IsTrue()) {
8078 PrintF("<true>");
8079 } else if (obj->IsFalse()) {
8080 PrintF("<false>");
8081 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008082 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008083 }
8084}
8085
8086
8087static int StackSize() {
8088 int n = 0;
8089 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8090 return n;
8091}
8092
8093
8094static void PrintTransition(Object* result) {
8095 // indentation
8096 { const int nmax = 80;
8097 int n = StackSize();
8098 if (n <= nmax)
8099 PrintF("%4d:%*s", n, n, "");
8100 else
8101 PrintF("%4d:%*s", n, nmax, "...");
8102 }
8103
8104 if (result == NULL) {
8105 // constructor calls
8106 JavaScriptFrameIterator it;
8107 JavaScriptFrame* frame = it.frame();
8108 if (frame->IsConstructor()) PrintF("new ");
8109 // function name
8110 Object* fun = frame->function();
8111 if (fun->IsJSFunction()) {
8112 PrintObject(JSFunction::cast(fun)->shared()->name());
8113 } else {
8114 PrintObject(fun);
8115 }
8116 // function arguments
8117 // (we are intentionally only printing the actually
8118 // supplied parameters, not all parameters required)
8119 PrintF("(this=");
8120 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008121 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122 for (int i = 0; i < length; i++) {
8123 PrintF(", ");
8124 PrintObject(frame->GetParameter(i));
8125 }
8126 PrintF(") {\n");
8127
8128 } else {
8129 // function result
8130 PrintF("} -> ");
8131 PrintObject(result);
8132 PrintF("\n");
8133 }
8134}
8135
8136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008137RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008138 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008139 NoHandleAllocation ha;
8140 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008141 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142}
8143
8144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008145RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 NoHandleAllocation ha;
8147 PrintTransition(args[0]);
8148 return args[0]; // return TOS
8149}
8150
8151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008153 NoHandleAllocation ha;
8154 ASSERT(args.length() == 1);
8155
8156#ifdef DEBUG
8157 if (args[0]->IsString()) {
8158 // If we have a string, assume it's a code "marker"
8159 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008160 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008162 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8163 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164 } else {
8165 PrintF("DebugPrint: ");
8166 }
8167 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008168 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008169 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008170 HeapObject::cast(args[0])->map()->Print();
8171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008173 // ShortPrint is available in release mode. Print is not.
8174 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175#endif
8176 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008177 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008178
8179 return args[0]; // return TOS
8180}
8181
8182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008183RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008184 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008185 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008186 isolate->PrintStack();
8187 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008188}
8189
8190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008191RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008192 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008193 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008194
8195 // According to ECMA-262, section 15.9.1, page 117, the precision of
8196 // the number in a Date object representing a particular instant in
8197 // time is milliseconds. Therefore, we floor the result of getting
8198 // the OS time.
8199 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008201}
8202
8203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008204RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008205 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008206 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008208 CONVERT_ARG_CHECKED(String, str, 0);
8209 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008211 CONVERT_ARG_CHECKED(JSArray, output, 1);
8212 RUNTIME_ASSERT(output->HasFastElements());
8213
8214 AssertNoAllocation no_allocation;
8215
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008216 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008217 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8218 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008219 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008220 result = DateParser::Parse(str->ToAsciiVector(),
8221 output_array,
8222 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008224 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008225 result = DateParser::Parse(str->ToUC16Vector(),
8226 output_array,
8227 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008228 }
8229
8230 if (result) {
8231 return *output;
8232 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008233 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234 }
8235}
8236
8237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008238RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008239 NoHandleAllocation ha;
8240 ASSERT(args.length() == 1);
8241
8242 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008243 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008245}
8246
8247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008250 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008252 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253}
8254
8255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257 NoHandleAllocation ha;
8258 ASSERT(args.length() == 1);
8259
8260 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262}
8263
8264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008265RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008266 ASSERT(args.length() == 1);
8267 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008269 return JSGlobalObject::cast(global)->global_receiver();
8270}
8271
8272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008273RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008275 ASSERT_EQ(1, args.length());
8276 CONVERT_ARG_CHECKED(String, source, 0);
8277
8278 Handle<Object> result = JsonParser::Parse(source);
8279 if (result.is_null()) {
8280 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008282 return Failure::Exception();
8283 }
8284 return *result;
8285}
8286
8287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008288RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008290 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008291 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008292
ager@chromium.org381abbb2009-02-25 13:23:22 +00008293 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008295 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8296 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008297 true,
8298 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008299 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008301 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8302 context,
8303 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 return *fun;
8305}
8306
8307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308static ObjectPair CompileGlobalEval(Isolate* isolate,
8309 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008310 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008311 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008312 // Deal with a normal eval call with a string argument. Compile it
8313 // and return the compiled function bound in the local context.
8314 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8315 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 Handle<Context>(isolate->context()),
8317 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008318 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008319 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 Handle<JSFunction> compiled =
8321 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8322 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008323 return MakePair(*compiled, *receiver);
8324}
8325
8326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008327RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008328 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008331 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008332 Handle<Object> receiver; // Will be overwritten.
8333
8334 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008335 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008336#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008338 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008339 StackFrameLocator locator;
8340 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008341 ASSERT(Context::cast(frame->context()) == *context);
8342#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008343
8344 // Find where the 'eval' symbol is bound. It is unaliased only if
8345 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008346 int index = -1;
8347 PropertyAttributes attributes = ABSENT;
8348 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8350 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008351 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008352 // Stop search when eval is found or when the global context is
8353 // reached.
8354 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008355 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008356 context = Handle<Context>(Context::cast(context->closure()->context()),
8357 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008358 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008359 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008360 }
8361 }
8362
iposva@chromium.org245aa852009-02-10 00:49:54 +00008363 // If eval could not be resolved, it has been deleted and we need to
8364 // throw a reference error.
8365 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008366 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008367 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 isolate->factory()->NewReferenceError("not_defined",
8369 HandleVector(&name, 1));
8370 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008371 }
8372
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008373 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008374 // 'eval' is not bound in the global context. Just call the function
8375 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008376 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008377 receiver = Handle<JSObject>(
8378 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008379 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008380 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008381 }
8382
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008383 // 'eval' is bound in the global context, but it may have been overwritten.
8384 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008385 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008386 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008387 return MakePair(*callee,
8388 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008389 }
8390
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008391 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008392 return CompileGlobalEval(isolate,
8393 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008394 args.at<Object>(2),
8395 static_cast<StrictModeFlag>(
8396 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008397}
8398
8399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008400RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008401 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008404 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008405
8406 // 'eval' is bound in the global context, but it may have been overwritten.
8407 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008409 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410 return MakePair(*callee,
8411 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008412 }
8413
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008414 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008415 return CompileGlobalEval(isolate,
8416 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008417 args.at<Object>(2),
8418 static_cast<StrictModeFlag>(
8419 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008420}
8421
8422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008423RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008424 // This utility adjusts the property attributes for newly created Function
8425 // object ("new Function(...)") by changing the map.
8426 // All it does is changing the prototype property to enumerable
8427 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008429 ASSERT(args.length() == 1);
8430 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431
8432 Handle<Map> map = func->shared()->strict_mode()
8433 ? isolate->strict_mode_function_instance_map()
8434 : isolate->function_instance_map();
8435
8436 ASSERT(func->map()->instance_type() == map->instance_type());
8437 ASSERT(func->map()->instance_size() == map->instance_size());
8438 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008439 return *func;
8440}
8441
8442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008443RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008444 // Allocate a block of memory in NewSpace (filled with a filler).
8445 // Use as fallback for allocation in generated code when NewSpace
8446 // is full.
8447 ASSERT(args.length() == 1);
8448 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8449 int size = size_smi->value();
8450 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8451 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452 Heap* heap = isolate->heap();
8453 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008454 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008455 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008456 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008457 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008459 }
8460 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008461 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008462}
8463
8464
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008465// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008466// array. Returns true if the element was pushed on the stack and
8467// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008468RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008469 ASSERT(args.length() == 2);
8470 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008471 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008472 RUNTIME_ASSERT(array->HasFastElements());
8473 int length = Smi::cast(array->length())->value();
8474 FixedArray* elements = FixedArray::cast(array->elements());
8475 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008477 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008478 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008479 // Strict not needed. Used for cycle detection in Array join implementation.
8480 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8481 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008482 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008485}
8486
8487
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008488/**
8489 * A simple visitor visits every element of Array's.
8490 * The backend storage can be a fixed array for fast elements case,
8491 * or a dictionary for sparse array. Since Dictionary is a subtype
8492 * of FixedArray, the class can be used by both fast and slow cases.
8493 * The second parameter of the constructor, fast_elements, specifies
8494 * whether the storage is a FixedArray or Dictionary.
8495 *
8496 * An index limit is used to deal with the situation that a result array
8497 * length overflows 32-bit non-negative integer.
8498 */
8499class ArrayConcatVisitor {
8500 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 ArrayConcatVisitor(Isolate* isolate,
8502 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008503 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008504 isolate_(isolate),
8505 storage_(Handle<FixedArray>::cast(
8506 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008507 index_offset_(0u),
8508 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008509
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008510 ~ArrayConcatVisitor() {
8511 clear_storage();
8512 }
8513
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008514 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008515 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008516 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008517
8518 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008519 if (index < static_cast<uint32_t>(storage_->length())) {
8520 storage_->set(index, *elm);
8521 return;
8522 }
8523 // Our initial estimate of length was foiled, possibly by
8524 // getters on the arrays increasing the length of later arrays
8525 // during iteration.
8526 // This shouldn't happen in anything but pathological cases.
8527 SetDictionaryMode(index);
8528 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008529 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008530 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008531 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008532 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008533 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008534 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008535 // Dictionary needed to grow.
8536 clear_storage();
8537 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008538 }
8539}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008540
8541 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008542 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8543 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008544 } else {
8545 index_offset_ += delta;
8546 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008547 }
8548
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008549 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008550 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008551 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008553 Handle<Map> map;
8554 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008555 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008556 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008558 }
8559 array->set_map(*map);
8560 array->set_length(*length);
8561 array->set_elements(*storage_);
8562 return array;
8563 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008564
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008565 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008566 // Convert storage to dictionary mode.
8567 void SetDictionaryMode(uint32_t index) {
8568 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008569 Handle<FixedArray> current_storage(*storage_);
8570 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008572 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8573 for (uint32_t i = 0; i < current_length; i++) {
8574 HandleScope loop_scope;
8575 Handle<Object> element(current_storage->get(i));
8576 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008577 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008579 if (!new_storage.is_identical_to(slow_storage)) {
8580 slow_storage = loop_scope.CloseAndEscape(new_storage);
8581 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 }
8583 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008584 clear_storage();
8585 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008586 fast_elements_ = false;
8587 }
8588
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008589 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 isolate_->global_handles()->Destroy(
8591 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008592 }
8593
8594 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008595 storage_ = Handle<FixedArray>::cast(
8596 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008597 }
8598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008599 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008600 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008601 // Index after last seen index. Always less than or equal to
8602 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008603 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008604 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008605};
8606
8607
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008608static uint32_t EstimateElementCount(Handle<JSArray> array) {
8609 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8610 int element_count = 0;
8611 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008612 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008613 // Fast elements can't have lengths that are not representable by
8614 // a 32-bit signed integer.
8615 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8616 int fast_length = static_cast<int>(length);
8617 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8618 for (int i = 0; i < fast_length; i++) {
8619 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008620 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008621 break;
8622 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008623 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008624 Handle<NumberDictionary> dictionary(
8625 NumberDictionary::cast(array->elements()));
8626 int capacity = dictionary->Capacity();
8627 for (int i = 0; i < capacity; i++) {
8628 Handle<Object> key(dictionary->KeyAt(i));
8629 if (dictionary->IsKey(*key)) {
8630 element_count++;
8631 }
8632 }
8633 break;
8634 }
8635 default:
8636 // External arrays are always dense.
8637 return length;
8638 }
8639 // As an estimate, we assume that the prototype doesn't contain any
8640 // inherited elements.
8641 return element_count;
8642}
8643
8644
8645
8646template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008647static void IterateExternalArrayElements(Isolate* isolate,
8648 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008649 bool elements_are_ints,
8650 bool elements_are_guaranteed_smis,
8651 ArrayConcatVisitor* visitor) {
8652 Handle<ExternalArrayClass> array(
8653 ExternalArrayClass::cast(receiver->elements()));
8654 uint32_t len = static_cast<uint32_t>(array->length());
8655
8656 ASSERT(visitor != NULL);
8657 if (elements_are_ints) {
8658 if (elements_are_guaranteed_smis) {
8659 for (uint32_t j = 0; j < len; j++) {
8660 HandleScope loop_scope;
8661 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8662 visitor->visit(j, e);
8663 }
8664 } else {
8665 for (uint32_t j = 0; j < len; j++) {
8666 HandleScope loop_scope;
8667 int64_t val = static_cast<int64_t>(array->get(j));
8668 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8669 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8670 visitor->visit(j, e);
8671 } else {
8672 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008674 visitor->visit(j, e);
8675 }
8676 }
8677 }
8678 } else {
8679 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 HandleScope loop_scope(isolate);
8681 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008682 visitor->visit(j, e);
8683 }
8684 }
8685}
8686
8687
8688// Used for sorting indices in a List<uint32_t>.
8689static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8690 uint32_t a = *ap;
8691 uint32_t b = *bp;
8692 return (a == b) ? 0 : (a < b) ? -1 : 1;
8693}
8694
8695
8696static void CollectElementIndices(Handle<JSObject> object,
8697 uint32_t range,
8698 List<uint32_t>* indices) {
8699 JSObject::ElementsKind kind = object->GetElementsKind();
8700 switch (kind) {
8701 case JSObject::FAST_ELEMENTS: {
8702 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8703 uint32_t length = static_cast<uint32_t>(elements->length());
8704 if (range < length) length = range;
8705 for (uint32_t i = 0; i < length; i++) {
8706 if (!elements->get(i)->IsTheHole()) {
8707 indices->Add(i);
8708 }
8709 }
8710 break;
8711 }
8712 case JSObject::DICTIONARY_ELEMENTS: {
8713 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008714 uint32_t capacity = dict->Capacity();
8715 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008716 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008717 Handle<Object> k(dict->KeyAt(j));
8718 if (dict->IsKey(*k)) {
8719 ASSERT(k->IsNumber());
8720 uint32_t index = static_cast<uint32_t>(k->Number());
8721 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008722 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008723 }
8724 }
8725 }
8726 break;
8727 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008728 default: {
8729 int dense_elements_length;
8730 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008731 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008732 dense_elements_length =
8733 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008734 break;
8735 }
8736 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008737 dense_elements_length =
8738 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008739 break;
8740 }
8741 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008742 dense_elements_length =
8743 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008744 break;
8745 }
8746 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008747 dense_elements_length =
8748 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 break;
8750 }
8751 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008752 dense_elements_length =
8753 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 break;
8755 }
8756 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008757 dense_elements_length =
8758 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008759 break;
8760 }
8761 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008762 dense_elements_length =
8763 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008764 break;
8765 }
8766 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008767 dense_elements_length =
8768 ExternalFloatArray::cast(object->elements())->length();
8769 break;
8770 }
8771 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8772 dense_elements_length =
8773 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 break;
8775 }
8776 default:
8777 UNREACHABLE();
8778 dense_elements_length = 0;
8779 break;
8780 }
8781 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8782 if (range <= length) {
8783 length = range;
8784 // We will add all indices, so we might as well clear it first
8785 // and avoid duplicates.
8786 indices->Clear();
8787 }
8788 for (uint32_t i = 0; i < length; i++) {
8789 indices->Add(i);
8790 }
8791 if (length == range) return; // All indices accounted for already.
8792 break;
8793 }
8794 }
8795
8796 Handle<Object> prototype(object->GetPrototype());
8797 if (prototype->IsJSObject()) {
8798 // The prototype will usually have no inherited element indices,
8799 // but we have to check.
8800 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8801 }
8802}
8803
8804
8805/**
8806 * A helper function that visits elements of a JSArray in numerical
8807 * order.
8808 *
8809 * The visitor argument called for each existing element in the array
8810 * with the element index and the element's value.
8811 * Afterwards it increments the base-index of the visitor by the array
8812 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008813 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008814 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008815static bool IterateElements(Isolate* isolate,
8816 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008817 ArrayConcatVisitor* visitor) {
8818 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8819 switch (receiver->GetElementsKind()) {
8820 case JSObject::FAST_ELEMENTS: {
8821 // Run through the elements FixedArray and use HasElement and GetElement
8822 // to check the prototype for missing elements.
8823 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8824 int fast_length = static_cast<int>(length);
8825 ASSERT(fast_length <= elements->length());
8826 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 HandleScope loop_scope(isolate);
8828 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008829 if (!element_value->IsTheHole()) {
8830 visitor->visit(j, element_value);
8831 } else if (receiver->HasElement(j)) {
8832 // Call GetElement on receiver, not its prototype, or getters won't
8833 // have the correct receiver.
8834 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008835 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008836 visitor->visit(j, element_value);
8837 }
8838 }
8839 break;
8840 }
8841 case JSObject::DICTIONARY_ELEMENTS: {
8842 Handle<NumberDictionary> dict(receiver->element_dictionary());
8843 List<uint32_t> indices(dict->Capacity() / 2);
8844 // Collect all indices in the object and the prototypes less
8845 // than length. This might introduce duplicates in the indices list.
8846 CollectElementIndices(receiver, length, &indices);
8847 indices.Sort(&compareUInt32);
8848 int j = 0;
8849 int n = indices.length();
8850 while (j < n) {
8851 HandleScope loop_scope;
8852 uint32_t index = indices[j];
8853 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008854 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008855 visitor->visit(index, element);
8856 // Skip to next different index (i.e., omit duplicates).
8857 do {
8858 j++;
8859 } while (j < n && indices[j] == index);
8860 }
8861 break;
8862 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008863 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8864 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8865 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008866 for (uint32_t j = 0; j < length; j++) {
8867 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8868 visitor->visit(j, e);
8869 }
8870 break;
8871 }
8872 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8873 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008875 break;
8876 }
8877 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8878 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008879 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008880 break;
8881 }
8882 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8883 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008884 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008885 break;
8886 }
8887 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8888 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008890 break;
8891 }
8892 case JSObject::EXTERNAL_INT_ELEMENTS: {
8893 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008894 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008895 break;
8896 }
8897 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8898 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008900 break;
8901 }
8902 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8903 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008904 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008905 break;
8906 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008907 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8908 IterateExternalArrayElements<ExternalDoubleArray, double>(
8909 isolate, receiver, false, false, visitor);
8910 break;
8911 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008912 default:
8913 UNREACHABLE();
8914 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008915 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008916 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008917 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008918}
8919
8920
8921/**
8922 * Array::concat implementation.
8923 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008924 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008925 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008926 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008927RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008928 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008930
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008931 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8932 int argument_count = static_cast<int>(arguments->length()->Number());
8933 RUNTIME_ASSERT(arguments->HasFastElements());
8934 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008935
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008936 // Pass 1: estimate the length and number of elements of the result.
8937 // The actual length can be larger if any of the arguments have getters
8938 // that mutate other arguments (but will otherwise be precise).
8939 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008940
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008941 uint32_t estimate_result_length = 0;
8942 uint32_t estimate_nof_elements = 0;
8943 {
8944 for (int i = 0; i < argument_count; i++) {
8945 HandleScope loop_scope;
8946 Handle<Object> obj(elements->get(i));
8947 uint32_t length_estimate;
8948 uint32_t element_estimate;
8949 if (obj->IsJSArray()) {
8950 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8951 length_estimate =
8952 static_cast<uint32_t>(array->length()->Number());
8953 element_estimate =
8954 EstimateElementCount(array);
8955 } else {
8956 length_estimate = 1;
8957 element_estimate = 1;
8958 }
8959 // Avoid overflows by capping at kMaxElementCount.
8960 if (JSObject::kMaxElementCount - estimate_result_length <
8961 length_estimate) {
8962 estimate_result_length = JSObject::kMaxElementCount;
8963 } else {
8964 estimate_result_length += length_estimate;
8965 }
8966 if (JSObject::kMaxElementCount - estimate_nof_elements <
8967 element_estimate) {
8968 estimate_nof_elements = JSObject::kMaxElementCount;
8969 } else {
8970 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008971 }
8972 }
8973 }
8974
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008975 // If estimated number of elements is more than half of length, a
8976 // fixed array (fast case) is more time and space-efficient than a
8977 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008978 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008979
8980 Handle<FixedArray> storage;
8981 if (fast_case) {
8982 // The backing storage array must have non-existing elements to
8983 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 storage = isolate->factory()->NewFixedArrayWithHoles(
8985 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008986 } else {
8987 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8988 uint32_t at_least_space_for = estimate_nof_elements +
8989 (estimate_nof_elements >> 2);
8990 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008991 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008992 }
8993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008995
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008996 for (int i = 0; i < argument_count; i++) {
8997 Handle<Object> obj(elements->get(i));
8998 if (obj->IsJSArray()) {
8999 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009001 return Failure::Exception();
9002 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009003 } else {
9004 visitor.visit(0, obj);
9005 visitor.increase_index_offset(1);
9006 }
9007 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009008
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009009 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009010}
9011
9012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013// This will not allocate (flatten the string), but it may run
9014// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009015RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009016 NoHandleAllocation ha;
9017 ASSERT(args.length() == 1);
9018
9019 CONVERT_CHECKED(String, string, args[0]);
9020 StringInputBuffer buffer(string);
9021 while (buffer.has_more()) {
9022 uint16_t character = buffer.GetNext();
9023 PrintF("%c", character);
9024 }
9025 return string;
9026}
9027
ager@chromium.org5ec48922009-05-05 07:25:34 +00009028// Moves all own elements of an object, that are below a limit, to positions
9029// starting at zero. All undefined values are placed after non-undefined values,
9030// and are followed by non-existing element. Does not change the length
9031// property.
9032// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009033RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009034 ASSERT(args.length() == 2);
9035 CONVERT_CHECKED(JSObject, object, args[0]);
9036 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9037 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038}
9039
9040
9041// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009042RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 ASSERT(args.length() == 2);
9044 CONVERT_CHECKED(JSArray, from, args[0]);
9045 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009046 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009047 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009048 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9049 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009050 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009051 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009052 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009053 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009054 Object* new_map;
9055 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009056 to->set_map(Map::cast(new_map));
9057 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009059 Object* obj;
9060 { MaybeObject* maybe_obj = from->ResetElements();
9061 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9062 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009063 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 return to;
9065}
9066
9067
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009068// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009069RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009071 CONVERT_CHECKED(JSObject, object, args[0]);
9072 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009074 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009075 } else if (object->IsJSArray()) {
9076 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009078 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 }
9080}
9081
9082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009083RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009084 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009085
9086 ASSERT_EQ(3, args.length());
9087
ager@chromium.orgac091b72010-05-05 07:34:42 +00009088 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009089 Handle<Object> key1 = args.at<Object>(1);
9090 Handle<Object> key2 = args.at<Object>(2);
9091
9092 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009093 if (!key1->ToArrayIndex(&index1)
9094 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009095 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009096 }
9097
ager@chromium.orgac091b72010-05-05 07:34:42 +00009098 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9099 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009100 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009101 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 RETURN_IF_EMPTY_HANDLE(isolate,
9105 SetElement(jsobject, index1, tmp2, kStrictMode));
9106 RETURN_IF_EMPTY_HANDLE(isolate,
9107 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009109 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009110}
9111
9112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009114// might have elements. Can either return keys (positive integers) or
9115// intervals (pair of a negative integer (-start-1) followed by a
9116// positive (length)) or undefined values.
9117// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009118RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009121 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009122 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009123 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124 // Create an array and get all the keys into it, then remove all the
9125 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009126 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 int keys_length = keys->length();
9128 for (int i = 0; i < keys_length; i++) {
9129 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009130 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009131 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132 // Zap invalid keys.
9133 keys->set_undefined(i);
9134 }
9135 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009138 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009141 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009142 uint32_t actual_length =
9143 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009144 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149 }
9150}
9151
9152
9153// DefineAccessor takes an optional final argument which is the
9154// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9155// to the way accessors are implemented, it is set for both the getter
9156// and setter on the first call to DefineAccessor and ignored on
9157// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009158RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9160 // Compute attributes.
9161 PropertyAttributes attributes = NONE;
9162 if (args.length() == 5) {
9163 CONVERT_CHECKED(Smi, attrs, args[4]);
9164 int value = attrs->value();
9165 // Only attribute bits should be set.
9166 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9167 attributes = static_cast<PropertyAttributes>(value);
9168 }
9169
9170 CONVERT_CHECKED(JSObject, obj, args[0]);
9171 CONVERT_CHECKED(String, name, args[1]);
9172 CONVERT_CHECKED(Smi, flag, args[2]);
9173 CONVERT_CHECKED(JSFunction, fun, args[3]);
9174 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9175}
9176
9177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009178RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179 ASSERT(args.length() == 3);
9180 CONVERT_CHECKED(JSObject, obj, args[0]);
9181 CONVERT_CHECKED(String, name, args[1]);
9182 CONVERT_CHECKED(Smi, flag, args[2]);
9183 return obj->LookupAccessor(name, flag->value() == 0);
9184}
9185
9186
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009187#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009188RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009189 ASSERT(args.length() == 0);
9190 return Execution::DebugBreakHelper();
9191}
9192
9193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194// Helper functions for wrapping and unwrapping stack frame ids.
9195static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009196 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197 return Smi::FromInt(id >> 2);
9198}
9199
9200
9201static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9202 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9203}
9204
9205
9206// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009207// args[0]: debug event listener function to set or null or undefined for
9208// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009209// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009210RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009211 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009212 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9213 args[0]->IsUndefined() ||
9214 args[0]->IsNull());
9215 Handle<Object> callback = args.at<Object>(0);
9216 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009217 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220}
9221
9222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009223RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009224 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009225 isolate->stack_guard()->DebugBreak();
9226 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227}
9228
9229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230static MaybeObject* DebugLookupResultValue(Heap* heap,
9231 Object* receiver,
9232 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009233 LookupResult* result,
9234 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009235 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009237 case NORMAL:
9238 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009239 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 }
9242 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009243 case FIELD:
9244 value =
9245 JSObject::cast(
9246 result->holder())->FastPropertyAt(result->GetFieldIndex());
9247 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009249 }
9250 return value;
9251 case CONSTANT_FUNCTION:
9252 return result->GetConstantFunction();
9253 case CALLBACKS: {
9254 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009255 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009256 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009257 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009258 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009259 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009260 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 maybe_value = heap->isolate()->pending_exception();
9262 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009263 if (caught_exception != NULL) {
9264 *caught_exception = true;
9265 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009267 }
9268 return value;
9269 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009271 }
9272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009273 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009274 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009275 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009276 case CONSTANT_TRANSITION:
9277 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009278 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 default:
9280 UNREACHABLE();
9281 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009282 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284}
9285
9286
ager@chromium.org32912102009-01-16 10:38:43 +00009287// Get debugger related details for an object property.
9288// args[0]: object holding property
9289// args[1]: name of the property
9290//
9291// The array returned contains the following information:
9292// 0: Property value
9293// 1: Property details
9294// 2: Property value is exception
9295// 3: Getter function if defined
9296// 4: Setter function if defined
9297// Items 2-4 are only filled if the property has either a getter or a setter
9298// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009299RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301
9302 ASSERT(args.length() == 2);
9303
9304 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9305 CONVERT_ARG_CHECKED(String, name, 1);
9306
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009307 // Make sure to set the current context to the context before the debugger was
9308 // entered (if the debugger is entered). The reason for switching context here
9309 // is that for some property lookups (accessors and interceptors) callbacks
9310 // into the embedding application can occour, and the embedding application
9311 // could have the assumption that its own global context is the current
9312 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 SaveContext save(isolate);
9314 if (isolate->debug()->InDebugger()) {
9315 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009316 }
9317
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009318 // Skip the global proxy as it has no properties and always delegates to the
9319 // real global object.
9320 if (obj->IsJSGlobalProxy()) {
9321 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9322 }
9323
9324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 // Check if the name is trivially convertible to an index and get the element
9326 // if so.
9327 uint32_t index;
9328 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009330 Object* element_or_char;
9331 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009332 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009333 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9334 return maybe_element_or_char;
9335 }
9336 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009337 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009339 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 }
9341
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009342 // Find the number of objects making up this.
9343 int length = LocalPrototypeChainLength(*obj);
9344
9345 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009346 Handle<JSObject> jsproto = obj;
9347 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009348 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009349 jsproto->LocalLookup(*name, &result);
9350 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009351 // LookupResult is not GC safe as it holds raw object pointers.
9352 // GC can happen later in this code so put the required fields into
9353 // local variables using handles when required for later use.
9354 PropertyType result_type = result.type();
9355 Handle<Object> result_callback_obj;
9356 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9358 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009359 }
9360 Smi* property_details = result.GetPropertyDetails().AsSmi();
9361 // DebugLookupResultValue can cause GC so details from LookupResult needs
9362 // to be copied to handles before this.
9363 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009364 Object* raw_value;
9365 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 DebugLookupResultValue(isolate->heap(), *obj, *name,
9367 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009368 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9369 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009371
9372 // If the callback object is a fixed array then it contains JavaScript
9373 // getter and/or setter.
9374 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9375 result_callback_obj->IsFixedArray();
9376 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009378 details->set(0, *value);
9379 details->set(1, property_details);
9380 if (hasJavaScriptAccessors) {
9381 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009382 caught_exception ? isolate->heap()->true_value()
9383 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009384 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9385 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9386 }
9387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009389 }
9390 if (i < length - 1) {
9391 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9392 }
9393 }
9394
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009396}
9397
9398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009399RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009400 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401
9402 ASSERT(args.length() == 2);
9403
9404 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9405 CONVERT_ARG_CHECKED(String, name, 1);
9406
9407 LookupResult result;
9408 obj->Lookup(*name, &result);
9409 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009412 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009413}
9414
9415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416// Return the property type calculated from the property details.
9417// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009418RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419 ASSERT(args.length() == 1);
9420 CONVERT_CHECKED(Smi, details, args[0]);
9421 PropertyType type = PropertyDetails(details).type();
9422 return Smi::FromInt(static_cast<int>(type));
9423}
9424
9425
9426// Return the property attribute calculated from the property details.
9427// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009428RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009429 ASSERT(args.length() == 1);
9430 CONVERT_CHECKED(Smi, details, args[0]);
9431 PropertyAttributes attributes = PropertyDetails(details).attributes();
9432 return Smi::FromInt(static_cast<int>(attributes));
9433}
9434
9435
9436// Return the property insertion index calculated from the property details.
9437// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009438RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439 ASSERT(args.length() == 1);
9440 CONVERT_CHECKED(Smi, details, args[0]);
9441 int index = PropertyDetails(details).index();
9442 return Smi::FromInt(index);
9443}
9444
9445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009446// Return property value from named interceptor.
9447// args[0]: object
9448// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009449RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451 ASSERT(args.length() == 2);
9452 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9453 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9454 CONVERT_ARG_CHECKED(String, name, 1);
9455
9456 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009457 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009458}
9459
9460
9461// Return element value from indexed interceptor.
9462// args[0]: object
9463// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009464RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 ASSERT(args.length() == 2);
9467 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9468 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9469 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9470
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009471 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472}
9473
9474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009475RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476 ASSERT(args.length() >= 1);
9477 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009478 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 if (isolate->debug()->break_id() == 0 ||
9480 break_id != isolate->debug()->break_id()) {
9481 return isolate->Throw(
9482 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483 }
9484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486}
9487
9488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009489RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009491 ASSERT(args.length() == 1);
9492
9493 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009494 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009495 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9496 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009497 if (!maybe_result->ToObject(&result)) return maybe_result;
9498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499
9500 // Count all frames which are relevant to debugging stack trace.
9501 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009503 if (id == StackFrame::NO_ID) {
9504 // If there is no JavaScript stack frame count is 0.
9505 return Smi::FromInt(0);
9506 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009507 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009508 return Smi::FromInt(n);
9509}
9510
9511
9512static const int kFrameDetailsFrameIdIndex = 0;
9513static const int kFrameDetailsReceiverIndex = 1;
9514static const int kFrameDetailsFunctionIndex = 2;
9515static const int kFrameDetailsArgumentCountIndex = 3;
9516static const int kFrameDetailsLocalCountIndex = 4;
9517static const int kFrameDetailsSourcePositionIndex = 5;
9518static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009519static const int kFrameDetailsAtReturnIndex = 7;
9520static const int kFrameDetailsDebuggerFrameIndex = 8;
9521static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522
9523// Return an array with frame details
9524// args[0]: number: break id
9525// args[1]: number: frame index
9526//
9527// The array returned contains the following information:
9528// 0: Frame id
9529// 1: Receiver
9530// 2: Function
9531// 3: Argument count
9532// 4: Local count
9533// 5: Source position
9534// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009535// 7: Is at return
9536// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537// Arguments name, value
9538// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009539// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009540RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 ASSERT(args.length() == 2);
9543
9544 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009546 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9547 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009548 if (!maybe_check->ToObject(&check)) return maybe_check;
9549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009550 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009551 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552
9553 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009555 if (id == StackFrame::NO_ID) {
9556 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009558 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009559 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009560 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009561 for (; !it.done(); it.Advance()) {
9562 if (count == index) break;
9563 count++;
9564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009567 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009568 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009570 // Traverse the saved contexts chain to find the active context for the
9571 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009573 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009574 save = save->prev();
9575 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009576 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577
9578 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009579 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580
9581 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009583 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584
9585 // Check for constructor frame.
9586 bool constructor = it.frame()->IsConstructor();
9587
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009588 // Get scope info and read from it for local variable information.
9589 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009590 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009591 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592
9593 // Get the context.
9594 Handle<Context> context(Context::cast(it.frame()->context()));
9595
9596 // Get the locals names and values into a temporary array.
9597 //
9598 // TODO(1240907): Hide compiler-introduced stack variables
9599 // (e.g. .result)? For users of the debugger, they will probably be
9600 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 Handle<FixedArray> locals =
9602 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009604 // Fill in the names of the locals.
9605 for (int i = 0; i < info.NumberOfLocals(); i++) {
9606 locals->set(i * 2, *info.LocalName(i));
9607 }
9608
9609 // Fill in the values of the locals.
9610 for (int i = 0; i < info.NumberOfLocals(); i++) {
9611 if (is_optimized_frame) {
9612 // If we are inspecting an optimized frame use undefined as the
9613 // value for all locals.
9614 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009615 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009616 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009617 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009618 } else if (i < info.number_of_stack_slots()) {
9619 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9621 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 // Traverse the context chain to the function context as all local
9623 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009624 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009625 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626 context = Handle<Context>(context->previous());
9627 }
9628 ASSERT(context->is_function_context());
9629 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009630 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009631 }
9632 }
9633
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009634 // Check whether this frame is positioned at return. If not top
9635 // frame or if the frame is optimized it cannot be at a return.
9636 bool at_return = false;
9637 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009638 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009639 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009640
9641 // If positioned just before return find the value to be returned and add it
9642 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009643 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009644 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009645 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009646 Address internal_frame_sp = NULL;
9647 while (!it2.done()) {
9648 if (it2.frame()->is_internal()) {
9649 internal_frame_sp = it2.frame()->sp();
9650 } else {
9651 if (it2.frame()->is_java_script()) {
9652 if (it2.frame()->id() == it.frame()->id()) {
9653 // The internal frame just before the JavaScript frame contains the
9654 // value to return on top. A debug break at return will create an
9655 // internal frame to store the return value (eax/rax/r0) before
9656 // entering the debug break exit frame.
9657 if (internal_frame_sp != NULL) {
9658 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 Handle<Object>(Memory::Object_at(internal_frame_sp),
9660 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009661 break;
9662 }
9663 }
9664 }
9665
9666 // Indicate that the previous frame was not an internal frame.
9667 internal_frame_sp = NULL;
9668 }
9669 it2.Advance();
9670 }
9671 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672
9673 // Now advance to the arguments adapter frame (if any). It contains all
9674 // the provided parameters whereas the function frame always have the number
9675 // of arguments matching the functions parameters. The rest of the
9676 // information (except for what is collected above) is the same.
9677 it.AdvanceToArgumentsFrame();
9678
9679 // Find the number of arguments to fill. At least fill the number of
9680 // parameters for the function and fill more if more parameters are provided.
9681 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009682 if (argument_count < it.frame()->ComputeParametersCount()) {
9683 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684 }
9685
9686 // Calculate the size of the result.
9687 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009688 2 * (argument_count + info.NumberOfLocals()) +
9689 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691
9692 // Add the frame id.
9693 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9694
9695 // Add the function (same as in function frame).
9696 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9697
9698 // Add the arguments count.
9699 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9700
9701 // Add the locals count
9702 details->set(kFrameDetailsLocalCountIndex,
9703 Smi::FromInt(info.NumberOfLocals()));
9704
9705 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009706 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009707 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710 }
9711
9712 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009714
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009715 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009716 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009718 // Add information on whether this frame is invoked in the debugger context.
9719 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 heap->ToBoolean(*save->context() ==
9721 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009722
9723 // Fill the dynamic part.
9724 int details_index = kFrameDetailsFirstDynamicIndex;
9725
9726 // Add arguments name and value.
9727 for (int i = 0; i < argument_count; i++) {
9728 // Name of the argument.
9729 if (i < info.number_of_parameters()) {
9730 details->set(details_index++, *info.parameter_name(i));
9731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009732 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 }
9734
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009735 // Parameter value. If we are inspecting an optimized frame, use
9736 // undefined as the value.
9737 //
9738 // TODO(3141533): We should be able to get the actual parameter
9739 // value for optimized frames.
9740 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009741 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009742 details->set(details_index++, it.frame()->GetParameter(i));
9743 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009745 }
9746 }
9747
9748 // Add locals name and value from the temporary copy from the function frame.
9749 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9750 details->set(details_index++, locals->get(i));
9751 }
9752
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009753 // Add the value being returned.
9754 if (at_return) {
9755 details->set(details_index++, *return_value);
9756 }
9757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009758 // Add the receiver (same as in function frame).
9759 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9760 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762 if (!receiver->IsJSObject()) {
9763 // If the receiver is NOT a JSObject we have hit an optimization
9764 // where a value object is not converted into a wrapped JS objects.
9765 // To hide this optimization from the debugger, we wrap the receiver
9766 // by creating correct wrapper object based on the calling frame's
9767 // global context.
9768 it.Advance();
9769 Handle<Context> calling_frames_global_context(
9770 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009771 receiver =
9772 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773 }
9774 details->set(kFrameDetailsReceiverIndex, *receiver);
9775
9776 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009778}
9779
9780
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009781// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009782static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009783 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009784 Handle<SerializedScopeInfo> serialized_scope_info,
9785 ScopeInfo<>& scope_info,
9786 Handle<Context> context,
9787 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009788 // Fill all context locals to the context extension.
9789 for (int i = Context::MIN_CONTEXT_SLOTS;
9790 i < scope_info.number_of_context_slots();
9791 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009792 int context_index = serialized_scope_info->ContextSlotIndex(
9793 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009794
9795 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009796 if (*scope_info.context_slot_name(i) !=
9797 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009798 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009799 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009800 SetProperty(scope_object,
9801 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009802 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009803 NONE,
9804 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009805 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009806 }
9807 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009808
9809 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009810}
9811
9812
9813// Create a plain JSObject which materializes the local scope for the specified
9814// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009815static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9816 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009817 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009818 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009819 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9820 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009821
9822 // Allocate and initialize a JSObject with all the arguments, stack locals
9823 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 Handle<JSObject> local_scope =
9825 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009826
9827 // First fill all parameters.
9828 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009829 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009830 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009831 SetProperty(local_scope,
9832 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009834 NONE,
9835 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009836 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009837 }
9838
9839 // Second fill all stack locals.
9840 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009841 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009843 SetProperty(local_scope,
9844 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009846 NONE,
9847 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009848 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009849 }
9850
9851 // Third fill all context locals.
9852 Handle<Context> frame_context(Context::cast(frame->context()));
9853 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009854 if (!CopyContextLocalsToScopeObject(isolate,
9855 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009856 function_context, local_scope)) {
9857 return Handle<JSObject>();
9858 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009859
9860 // Finally copy any properties from the function context extension. This will
9861 // be variables introduced by eval.
9862 if (function_context->closure() == *function) {
9863 if (function_context->has_extension() &&
9864 !function_context->IsGlobalContext()) {
9865 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009866 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009867 for (int i = 0; i < keys->length(); i++) {
9868 // Names of variables introduced by eval are strings.
9869 ASSERT(keys->get(i)->IsString());
9870 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009871 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009872 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009873 SetProperty(local_scope,
9874 key,
9875 GetProperty(ext, key),
9876 NONE,
9877 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009878 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009879 }
9880 }
9881 }
9882 return local_scope;
9883}
9884
9885
9886// Create a plain JSObject which materializes the closure content for the
9887// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009888static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9889 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009890 ASSERT(context->is_function_context());
9891
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009892 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009893 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9894 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009895
9896 // Allocate and initialize a JSObject with all the content of theis function
9897 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009898 Handle<JSObject> closure_scope =
9899 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009900
9901 // Check whether the arguments shadow object exists.
9902 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 shared->scope_info()->ContextSlotIndex(
9904 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009905 if (arguments_shadow_index >= 0) {
9906 // In this case all the arguments are available in the arguments shadow
9907 // object.
9908 Handle<JSObject> arguments_shadow(
9909 JSObject::cast(context->get(arguments_shadow_index)));
9910 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009911 // We don't expect exception-throwing getters on the arguments shadow.
9912 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009913 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009914 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009915 SetProperty(closure_scope,
9916 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009917 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009918 NONE,
9919 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009920 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009921 }
9922 }
9923
9924 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009925 if (!CopyContextLocalsToScopeObject(isolate,
9926 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009927 context, closure_scope)) {
9928 return Handle<JSObject>();
9929 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009930
9931 // Finally copy any properties from the function context extension. This will
9932 // be variables introduced by eval.
9933 if (context->has_extension()) {
9934 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009935 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009936 for (int i = 0; i < keys->length(); i++) {
9937 // Names of variables introduced by eval are strings.
9938 ASSERT(keys->get(i)->IsString());
9939 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009940 RETURN_IF_EMPTY_HANDLE_VALUE(
9941 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009942 SetProperty(closure_scope,
9943 key,
9944 GetProperty(ext, key),
9945 NONE,
9946 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009947 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009948 }
9949 }
9950
9951 return closure_scope;
9952}
9953
9954
9955// Iterate over the actual scopes visible from a stack frame. All scopes are
9956// backed by an actual context except the local scope, which is inserted
9957// "artifically" in the context chain.
9958class ScopeIterator {
9959 public:
9960 enum ScopeType {
9961 ScopeTypeGlobal = 0,
9962 ScopeTypeLocal,
9963 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009964 ScopeTypeClosure,
9965 // Every catch block contains an implicit with block (its parameter is
9966 // a JSContextExtensionObject) that extends current scope with a variable
9967 // holding exception object. Such with blocks are treated as scopes of their
9968 // own type.
9969 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009970 };
9971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9973 : isolate_(isolate),
9974 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009975 function_(JSFunction::cast(frame->function())),
9976 context_(Context::cast(frame->context())),
9977 local_done_(false),
9978 at_local_(false) {
9979
9980 // Check whether the first scope is actually a local scope.
9981 if (context_->IsGlobalContext()) {
9982 // If there is a stack slot for .result then this local scope has been
9983 // created for evaluating top level code and it is not a real local scope.
9984 // Checking for the existence of .result seems fragile, but the scope info
9985 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009986 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009987 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009988 at_local_ = index < 0;
9989 } else if (context_->is_function_context()) {
9990 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009991 } else if (context_->closure() != *function_) {
9992 // The context_ is a with block from the outer function.
9993 ASSERT(context_->has_extension());
9994 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009995 }
9996 }
9997
9998 // More scopes?
9999 bool Done() { return context_.is_null(); }
10000
10001 // Move to the next scope.
10002 void Next() {
10003 // If at a local scope mark the local scope as passed.
10004 if (at_local_) {
10005 at_local_ = false;
10006 local_done_ = true;
10007
10008 // If the current context is not associated with the local scope the
10009 // current context is the next real scope, so don't move to the next
10010 // context in this case.
10011 if (context_->closure() != *function_) {
10012 return;
10013 }
10014 }
10015
10016 // The global scope is always the last in the chain.
10017 if (context_->IsGlobalContext()) {
10018 context_ = Handle<Context>();
10019 return;
10020 }
10021
10022 // Move to the next context.
10023 if (context_->is_function_context()) {
10024 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10025 } else {
10026 context_ = Handle<Context>(context_->previous());
10027 }
10028
10029 // If passing the local scope indicate that the current scope is now the
10030 // local scope.
10031 if (!local_done_ &&
10032 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10033 at_local_ = true;
10034 }
10035 }
10036
10037 // Return the type of the current scope.
10038 int Type() {
10039 if (at_local_) {
10040 return ScopeTypeLocal;
10041 }
10042 if (context_->IsGlobalContext()) {
10043 ASSERT(context_->global()->IsGlobalObject());
10044 return ScopeTypeGlobal;
10045 }
10046 if (context_->is_function_context()) {
10047 return ScopeTypeClosure;
10048 }
10049 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010050 // Current scope is either an explicit with statement or a with statement
10051 // implicitely generated for a catch block.
10052 // If the extension object here is a JSContextExtensionObject then
10053 // current with statement is one frome a catch block otherwise it's a
10054 // regular with statement.
10055 if (context_->extension()->IsJSContextExtensionObject()) {
10056 return ScopeTypeCatch;
10057 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010058 return ScopeTypeWith;
10059 }
10060
10061 // Return the JavaScript object with the content of the current scope.
10062 Handle<JSObject> ScopeObject() {
10063 switch (Type()) {
10064 case ScopeIterator::ScopeTypeGlobal:
10065 return Handle<JSObject>(CurrentContext()->global());
10066 break;
10067 case ScopeIterator::ScopeTypeLocal:
10068 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010069 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010070 break;
10071 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010072 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010073 // Return the with object.
10074 return Handle<JSObject>(CurrentContext()->extension());
10075 break;
10076 case ScopeIterator::ScopeTypeClosure:
10077 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010079 break;
10080 }
10081 UNREACHABLE();
10082 return Handle<JSObject>();
10083 }
10084
10085 // Return the context for this scope. For the local context there might not
10086 // be an actual context.
10087 Handle<Context> CurrentContext() {
10088 if (at_local_ && context_->closure() != *function_) {
10089 return Handle<Context>();
10090 }
10091 return context_;
10092 }
10093
10094#ifdef DEBUG
10095 // Debug print of the content of the current scope.
10096 void DebugPrint() {
10097 switch (Type()) {
10098 case ScopeIterator::ScopeTypeGlobal:
10099 PrintF("Global:\n");
10100 CurrentContext()->Print();
10101 break;
10102
10103 case ScopeIterator::ScopeTypeLocal: {
10104 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010105 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010106 scope_info.Print();
10107 if (!CurrentContext().is_null()) {
10108 CurrentContext()->Print();
10109 if (CurrentContext()->has_extension()) {
10110 Handle<JSObject> extension =
10111 Handle<JSObject>(CurrentContext()->extension());
10112 if (extension->IsJSContextExtensionObject()) {
10113 extension->Print();
10114 }
10115 }
10116 }
10117 break;
10118 }
10119
10120 case ScopeIterator::ScopeTypeWith: {
10121 PrintF("With:\n");
10122 Handle<JSObject> extension =
10123 Handle<JSObject>(CurrentContext()->extension());
10124 extension->Print();
10125 break;
10126 }
10127
ager@chromium.orga1645e22009-09-09 19:27:10 +000010128 case ScopeIterator::ScopeTypeCatch: {
10129 PrintF("Catch:\n");
10130 Handle<JSObject> extension =
10131 Handle<JSObject>(CurrentContext()->extension());
10132 extension->Print();
10133 break;
10134 }
10135
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010136 case ScopeIterator::ScopeTypeClosure: {
10137 PrintF("Closure:\n");
10138 CurrentContext()->Print();
10139 if (CurrentContext()->has_extension()) {
10140 Handle<JSObject> extension =
10141 Handle<JSObject>(CurrentContext()->extension());
10142 if (extension->IsJSContextExtensionObject()) {
10143 extension->Print();
10144 }
10145 }
10146 break;
10147 }
10148
10149 default:
10150 UNREACHABLE();
10151 }
10152 PrintF("\n");
10153 }
10154#endif
10155
10156 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010157 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010158 JavaScriptFrame* frame_;
10159 Handle<JSFunction> function_;
10160 Handle<Context> context_;
10161 bool local_done_;
10162 bool at_local_;
10163
10164 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10165};
10166
10167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010168RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010169 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010170 ASSERT(args.length() == 2);
10171
10172 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010173 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010174 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10175 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010176 if (!maybe_check->ToObject(&check)) return maybe_check;
10177 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010178 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10179
10180 // Get the frame where the debugging is performed.
10181 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010182 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010183 JavaScriptFrame* frame = it.frame();
10184
10185 // Count the visible scopes.
10186 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010187 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010188 n++;
10189 }
10190
10191 return Smi::FromInt(n);
10192}
10193
10194
10195static const int kScopeDetailsTypeIndex = 0;
10196static const int kScopeDetailsObjectIndex = 1;
10197static const int kScopeDetailsSize = 2;
10198
10199// Return an array with scope details
10200// args[0]: number: break id
10201// args[1]: number: frame index
10202// args[2]: number: scope index
10203//
10204// The array returned contains the following information:
10205// 0: Scope type
10206// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010207RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010209 ASSERT(args.length() == 3);
10210
10211 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010212 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010213 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10214 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010215 if (!maybe_check->ToObject(&check)) return maybe_check;
10216 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010217 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10218 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10219
10220 // Get the frame where the debugging is performed.
10221 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010222 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010223 JavaScriptFrame* frame = frame_it.frame();
10224
10225 // Find the requested scope.
10226 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010228 for (; !it.Done() && n < index; it.Next()) {
10229 n++;
10230 }
10231 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010233 }
10234
10235 // Calculate the size of the result.
10236 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010237 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010238
10239 // Fill in scope details.
10240 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010241 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010242 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010243 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010246}
10247
10248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010249RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010251 ASSERT(args.length() == 0);
10252
10253#ifdef DEBUG
10254 // Print the scopes for the top frame.
10255 StackFrameLocator locator;
10256 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010257 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010258 it.DebugPrint();
10259 }
10260#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010262}
10263
10264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010265RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010267 ASSERT(args.length() == 1);
10268
10269 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010270 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010271 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10272 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010273 if (!maybe_result->ToObject(&result)) return maybe_result;
10274 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010275
10276 // Count all archived V8 threads.
10277 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 for (ThreadState* thread =
10279 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010280 thread != NULL;
10281 thread = thread->Next()) {
10282 n++;
10283 }
10284
10285 // Total number of threads is current thread and archived threads.
10286 return Smi::FromInt(n + 1);
10287}
10288
10289
10290static const int kThreadDetailsCurrentThreadIndex = 0;
10291static const int kThreadDetailsThreadIdIndex = 1;
10292static const int kThreadDetailsSize = 2;
10293
10294// Return an array with thread details
10295// args[0]: number: break id
10296// args[1]: number: thread index
10297//
10298// The array returned contains the following information:
10299// 0: Is current thread?
10300// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010301RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010303 ASSERT(args.length() == 2);
10304
10305 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010306 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010307 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10308 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010309 if (!maybe_check->ToObject(&check)) return maybe_check;
10310 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010311 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10312
10313 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010314 Handle<FixedArray> details =
10315 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010316
10317 // Thread index 0 is current thread.
10318 if (index == 0) {
10319 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 details->set(kThreadDetailsCurrentThreadIndex,
10321 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010322 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010323 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010324 } else {
10325 // Find the thread with the requested index.
10326 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 ThreadState* thread =
10328 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010329 while (index != n && thread != NULL) {
10330 thread = thread->Next();
10331 n++;
10332 }
10333 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010335 }
10336
10337 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010338 details->set(kThreadDetailsCurrentThreadIndex,
10339 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010340 details->set(kThreadDetailsThreadIdIndex,
10341 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010342 }
10343
10344 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010346}
10347
10348
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010349// Sets the disable break state
10350// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010351RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010352 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010353 ASSERT(args.length() == 1);
10354 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 isolate->debug()->set_disable_break(disable_break);
10356 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010357}
10358
10359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010360RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 ASSERT(args.length() == 1);
10363
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010364 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10365 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 // Find the number of break points
10367 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 Handle<FixedArray>::cast(break_locations));
10372}
10373
10374
10375// Set a break point in a function
10376// args[0]: function
10377// args[1]: number: break source position (within the function source)
10378// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010379RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010382 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10383 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10385 RUNTIME_ASSERT(source_position >= 0);
10386 Handle<Object> break_point_object_arg = args.at<Object>(2);
10387
10388 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010389 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10390 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010392 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393}
10394
10395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10397 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010398 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399 // Iterate the heap looking for SharedFunctionInfo generated from the
10400 // script. The inner most SharedFunctionInfo containing the source position
10401 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010402 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 // which is found is not compiled it is compiled and the heap is iterated
10404 // again as the compilation might create inner functions from the newly
10405 // compiled function and the actual requested break point might be in one of
10406 // these functions.
10407 bool done = false;
10408 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010409 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 while (!done) {
10412 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010413 for (HeapObject* obj = iterator.next();
10414 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415 if (obj->IsSharedFunctionInfo()) {
10416 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10417 if (shared->script() == *script) {
10418 // If the SharedFunctionInfo found has the requested script data and
10419 // contains the source position it is a candidate.
10420 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010421 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010422 start_position = shared->start_position();
10423 }
10424 if (start_position <= position &&
10425 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010426 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 // candidate this is the new candidate.
10428 if (target.is_null()) {
10429 target_start_position = start_position;
10430 target = shared;
10431 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010432 if (target_start_position == start_position &&
10433 shared->end_position() == target->end_position()) {
10434 // If a top-level function contain only one function
10435 // declartion the source for the top-level and the function is
10436 // the same. In that case prefer the non top-level function.
10437 if (!shared->is_toplevel()) {
10438 target_start_position = start_position;
10439 target = shared;
10440 }
10441 } else if (target_start_position <= start_position &&
10442 shared->end_position() <= target->end_position()) {
10443 // This containment check includes equality as a function inside
10444 // a top-level function can share either start or end position
10445 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 target_start_position = start_position;
10447 target = shared;
10448 }
10449 }
10450 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 }
10452 }
10453 }
10454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 }
10458
10459 // If the candidate found is compiled we are done. NOTE: when lazy
10460 // compilation of inner functions is introduced some additional checking
10461 // needs to be done here to compile inner functions.
10462 done = target->is_compiled();
10463 if (!done) {
10464 // If the candidate is not compiled compile it to reveal any inner
10465 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010466 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467 }
10468 }
10469
10470 return *target;
10471}
10472
10473
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010474// Changes the state of a break point in a script and returns source position
10475// where break point was set. NOTE: Regarding performance see the NOTE for
10476// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477// args[0]: script to set break point in
10478// args[1]: number: break source position (within the script source)
10479// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010480RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010481 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010482 ASSERT(args.length() == 3);
10483 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10484 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10485 RUNTIME_ASSERT(source_position >= 0);
10486 Handle<Object> break_point_object_arg = args.at<Object>(2);
10487
10488 // Get the script from the script wrapper.
10489 RUNTIME_ASSERT(wrapper->value()->IsScript());
10490 Handle<Script> script(Script::cast(wrapper->value()));
10491
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010492 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010494 if (!result->IsUndefined()) {
10495 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10496 // Find position within function. The script position might be before the
10497 // source position of the first function.
10498 int position;
10499 if (shared->start_position() > source_position) {
10500 position = 0;
10501 } else {
10502 position = source_position - shared->start_position();
10503 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010504 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010505 position += shared->start_position();
10506 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010508 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509}
10510
10511
10512// Clear a break point
10513// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010514RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 ASSERT(args.length() == 1);
10517 Handle<Object> break_point_object_arg = args.at<Object>(0);
10518
10519 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010520 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010523}
10524
10525
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010526// Change the state of break on exceptions.
10527// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10528// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010529RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010530 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010532 RUNTIME_ASSERT(args[0]->IsNumber());
10533 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010535 // If the number doesn't match an enum value, the ChangeBreakOnException
10536 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010537 ExceptionBreakType type =
10538 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010539 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 isolate->debug()->ChangeBreakOnException(type, enable);
10541 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542}
10543
10544
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010545// Returns the state of break on exceptions
10546// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010547RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010548 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010549 ASSERT(args.length() == 1);
10550 RUNTIME_ASSERT(args[0]->IsNumber());
10551
10552 ExceptionBreakType type =
10553 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010554 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010555 return Smi::FromInt(result);
10556}
10557
10558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559// Prepare for stepping
10560// args[0]: break id for checking execution state
10561// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010562// args[2]: number of times to perform the step, for step out it is the number
10563// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566 ASSERT(args.length() == 3);
10567 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010568 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010569 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10570 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010571 if (!maybe_check->ToObject(&check)) return maybe_check;
10572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 }
10576
10577 // Get the step action and check validity.
10578 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10579 if (step_action != StepIn &&
10580 step_action != StepNext &&
10581 step_action != StepOut &&
10582 step_action != StepInMin &&
10583 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585 }
10586
10587 // Get the number of steps.
10588 int step_count = NumberToInt32(args[2]);
10589 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 }
10592
ager@chromium.orga1645e22009-09-09 19:27:10 +000010593 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10598 step_count);
10599 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600}
10601
10602
10603// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010604RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010606 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 isolate->debug()->ClearStepping();
10608 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609}
10610
10611
10612// Creates a copy of the with context chain. The copy of the context chain is
10613// is linked to the function context supplied.
10614static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10615 Handle<Context> function_context) {
10616 // At the bottom of the chain. Return the function context to link to.
10617 if (context_chain->is_function_context()) {
10618 return function_context;
10619 }
10620
10621 // Recursively copy the with contexts.
10622 Handle<Context> previous(context_chain->previous());
10623 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010624 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625 return context->GetIsolate()->factory()->NewWithContext(
10626 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627}
10628
10629
10630// Helper function to find or create the arguments object for
10631// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632static Handle<Object> GetArgumentsObject(Isolate* isolate,
10633 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010635 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 const ScopeInfo<>* sinfo,
10637 Handle<Context> function_context) {
10638 // Try to find the value of 'arguments' to pass as parameter. If it is not
10639 // found (that is the debugged function does not reference 'arguments' and
10640 // does not support eval) then create an 'arguments' object.
10641 int index;
10642 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010643 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646 }
10647 }
10648
10649 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10651 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010652 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010653 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 }
10655 }
10656
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010657 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 Handle<JSObject> arguments =
10659 isolate->factory()->NewArgumentsObject(function, length);
10660 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010661
10662 AssertNoAllocation no_gc;
10663 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010665 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010666 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010667 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 return arguments;
10669}
10670
10671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672static const char kSourceStr[] =
10673 "(function(arguments,__source__){return eval(__source__);})";
10674
10675
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010677// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678// extension part has all the parameters and locals of the function on the
10679// stack frame. A function which calls eval with the code to evaluate is then
10680// compiled in this context and called in this context. As this context
10681// replaces the context of the function on the stack frame a new (empty)
10682// function is created as well to be used as the closure for the context.
10683// This function and the context acts as replacements for the function on the
10684// stack frame presenting the same view of the values of parameters and
10685// local variables as if the piece of JavaScript was evaluated at the point
10686// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010687RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689
10690 // Check the execution state and decode arguments frame and source to be
10691 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010692 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010693 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010694 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10695 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010696 if (!maybe_check_result->ToObject(&check_result)) {
10697 return maybe_check_result;
10698 }
10699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10701 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010702 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010703 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010704
10705 // Handle the processing of break.
10706 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707
10708 // Get the frame where the debugging is performed.
10709 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010710 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711 JavaScriptFrame* frame = it.frame();
10712 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010713 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010714 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010715
10716 // Traverse the saved contexts chain to find the active context for the
10717 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010718 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010719 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 save = save->prev();
10721 }
10722 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010723 SaveContext savex(isolate);
10724 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010725
10726 // Create the (empty) function replacing the function on the stack frame for
10727 // the purpose of evaluating in the context created below. It is important
10728 // that this function does not describe any parameters and local variables
10729 // in the context. If it does then this will cause problems with the lookup
10730 // in Context::Lookup, where context slots for parameters and local variables
10731 // are looked at before the extension object.
10732 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10734 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 go_between->set_context(function->context());
10736#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010737 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10739 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10740#endif
10741
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010743 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10744 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745
10746 // Allocate a new context for the debug evaluation and set the extension
10747 // object build.
10748 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10750 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010751 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010753 Handle<Context> frame_context(Context::cast(frame->context()));
10754 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755 context = CopyWithContextChain(frame_context, context);
10756
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010757 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010759 Handle<JSObject>::cast(additional_context), false);
10760 }
10761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 // Wrap the evaluation statement in a new function compiled in the newly
10763 // created context. The function has one parameter which has to be called
10764 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010765 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010766 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 isolate->factory()->NewStringFromAscii(
10770 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010771
10772 // Currently, the eval code will be executed in non-strict mode,
10773 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010774 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010775 Compiler::CompileEval(function_source,
10776 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010777 context->IsGlobalContext(),
10778 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010779 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010781 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782
10783 // Invoke the result of the compilation to get the evaluation function.
10784 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786 Handle<Object> evaluation_function =
10787 Execution::Call(compiled_function, receiver, 0, NULL,
10788 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010789 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010791 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10792 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010793 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794
10795 // Invoke the evaluation function and return the result.
10796 const int argc = 2;
10797 Object** argv[argc] = { arguments.location(),
10798 Handle<Object>::cast(source).location() };
10799 Handle<Object> result =
10800 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10801 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010802 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010803
10804 // Skip the global proxy as it has no properties and always delegates to the
10805 // real global object.
10806 if (result->IsJSGlobalProxy()) {
10807 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10808 }
10809
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810 return *result;
10811}
10812
10813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010814RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816
10817 // Check the execution state and decode arguments frame and source to be
10818 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010819 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010820 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010821 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10822 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010823 if (!maybe_check_result->ToObject(&check_result)) {
10824 return maybe_check_result;
10825 }
10826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010828 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010829 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010830
10831 // Handle the processing of break.
10832 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010833
10834 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010835 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838 top = top->prev();
10839 }
10840 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010841 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 }
10843
10844 // Get the global context now set to the top context from before the
10845 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010848 bool is_global = true;
10849
10850 if (additional_context->IsJSObject()) {
10851 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10853 isolate->factory()->empty_string(),
10854 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010855 go_between->set_context(*context);
10856 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010857 isolate->factory()->NewFunctionContext(
10858 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010859 context->set_extension(JSObject::cast(*additional_context));
10860 is_global = false;
10861 }
10862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010864 // Currently, the eval code will be executed in non-strict mode,
10865 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010866 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010867 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010868 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870 Handle<JSFunction>(
10871 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10872 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
10874 // Invoke the result of the compilation to get the evaluation function.
10875 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010877 Handle<Object> result =
10878 Execution::Call(compiled_function, receiver, 0, NULL,
10879 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010880 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881 return *result;
10882}
10883
10884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010885RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010886 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010887 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010891
10892 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010893 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010894 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10895 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10896 // because using
10897 // instances->set(i, *GetScriptWrapper(script))
10898 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10899 // already have deferenced the instances handle.
10900 Handle<JSValue> wrapper = GetScriptWrapper(script);
10901 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902 }
10903
10904 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010905 Handle<JSObject> result =
10906 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 Handle<JSArray>::cast(result)->SetContent(*instances);
10908 return *result;
10909}
10910
10911
10912// Helper function used by Runtime_DebugReferencedBy below.
10913static int DebugReferencedBy(JSObject* target,
10914 Object* instance_filter, int max_references,
10915 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 JSFunction* arguments_function) {
10917 NoHandleAllocation ha;
10918 AssertNoAllocation no_alloc;
10919
10920 // Iterate the heap.
10921 int count = 0;
10922 JSObject* last = NULL;
10923 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010924 HeapObject* heap_obj = NULL;
10925 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 (max_references == 0 || count < max_references)) {
10927 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928 if (heap_obj->IsJSObject()) {
10929 // Skip context extension objects and argument arrays as these are
10930 // checked in the context of functions using them.
10931 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010932 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 obj->map()->constructor() == arguments_function) {
10934 continue;
10935 }
10936
10937 // Check if the JS object has a reference to the object looked for.
10938 if (obj->ReferencesObject(target)) {
10939 // Check instance filter if supplied. This is normally used to avoid
10940 // references from mirror objects (see Runtime_IsInPrototypeChain).
10941 if (!instance_filter->IsUndefined()) {
10942 Object* V = obj;
10943 while (true) {
10944 Object* prototype = V->GetPrototype();
10945 if (prototype->IsNull()) {
10946 break;
10947 }
10948 if (instance_filter == prototype) {
10949 obj = NULL; // Don't add this object.
10950 break;
10951 }
10952 V = prototype;
10953 }
10954 }
10955
10956 if (obj != NULL) {
10957 // Valid reference found add to instance array if supplied an update
10958 // count.
10959 if (instances != NULL && count < instances_size) {
10960 instances->set(count, obj);
10961 }
10962 last = obj;
10963 count++;
10964 }
10965 }
10966 }
10967 }
10968
10969 // Check for circular reference only. This can happen when the object is only
10970 // referenced from mirrors and has a circular reference in which case the
10971 // object is not really alive and would have been garbage collected if not
10972 // referenced from the mirror.
10973 if (count == 1 && last == target) {
10974 count = 0;
10975 }
10976
10977 // Return the number of referencing objects found.
10978 return count;
10979}
10980
10981
10982// Scan the heap for objects with direct references to an object
10983// args[0]: the object to find references to
10984// args[1]: constructor function for instances to exclude (Mirror)
10985// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010986RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 ASSERT(args.length() == 3);
10988
10989 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991
10992 // Check parameters.
10993 CONVERT_CHECKED(JSObject, target, args[0]);
10994 Object* instance_filter = args[1];
10995 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10996 instance_filter->IsJSObject());
10997 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10998 RUNTIME_ASSERT(max_references >= 0);
10999
11000 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011002 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011003 JSFunction* arguments_function =
11004 JSFunction::cast(arguments_boilerplate->map()->constructor());
11005
11006 // Get the number of referencing objects.
11007 int count;
11008 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011009 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011010
11011 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011012 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011014 if (!maybe_object->ToObject(&object)) return maybe_object;
11015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 FixedArray* instances = FixedArray::cast(object);
11017
11018 // Fill the referencing objects.
11019 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011020 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021
11022 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011023 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011024 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11025 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011026 if (!maybe_result->ToObject(&result)) return maybe_result;
11027 }
11028 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029 return result;
11030}
11031
11032
11033// Helper function used by Runtime_DebugConstructedBy below.
11034static int DebugConstructedBy(JSFunction* constructor, int max_references,
11035 FixedArray* instances, int instances_size) {
11036 AssertNoAllocation no_alloc;
11037
11038 // Iterate the heap.
11039 int count = 0;
11040 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011041 HeapObject* heap_obj = NULL;
11042 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 (max_references == 0 || count < max_references)) {
11044 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045 if (heap_obj->IsJSObject()) {
11046 JSObject* obj = JSObject::cast(heap_obj);
11047 if (obj->map()->constructor() == constructor) {
11048 // Valid reference found add to instance array if supplied an update
11049 // count.
11050 if (instances != NULL && count < instances_size) {
11051 instances->set(count, obj);
11052 }
11053 count++;
11054 }
11055 }
11056 }
11057
11058 // Return the number of referencing objects found.
11059 return count;
11060}
11061
11062
11063// Scan the heap for objects constructed by a specific function.
11064// args[0]: the constructor to find instances of
11065// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011066RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067 ASSERT(args.length() == 2);
11068
11069 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011071
11072 // Check parameters.
11073 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11074 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11075 RUNTIME_ASSERT(max_references >= 0);
11076
11077 // Get the number of referencing objects.
11078 int count;
11079 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11080
11081 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011082 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011083 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011084 if (!maybe_object->ToObject(&object)) return maybe_object;
11085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011086 FixedArray* instances = FixedArray::cast(object);
11087
11088 // Fill the referencing objects.
11089 count = DebugConstructedBy(constructor, max_references, instances, count);
11090
11091 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011092 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11094 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011095 if (!maybe_result->ToObject(&result)) return maybe_result;
11096 }
11097 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011098 return result;
11099}
11100
11101
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011102// Find the effective prototype object as returned by __proto__.
11103// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011104RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011105 ASSERT(args.length() == 1);
11106
11107 CONVERT_CHECKED(JSObject, obj, args[0]);
11108
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011109 // Use the __proto__ accessor.
11110 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011111}
11112
11113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011114RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011115 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011116 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011118}
11119
11120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011121RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011122#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011124 ASSERT(args.length() == 1);
11125 // Get the function and make sure it is compiled.
11126 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011127 Handle<SharedFunctionInfo> shared(func->shared());
11128 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011129 return Failure::Exception();
11130 }
11131 func->code()->PrintLn();
11132#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011134}
ager@chromium.org9085a012009-05-11 19:22:57 +000011135
11136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011137RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011138#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011139 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011140 ASSERT(args.length() == 1);
11141 // Get the function and make sure it is compiled.
11142 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011143 Handle<SharedFunctionInfo> shared(func->shared());
11144 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011145 return Failure::Exception();
11146 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011147 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011148#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011149 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011150}
11151
11152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011154 NoHandleAllocation ha;
11155 ASSERT(args.length() == 1);
11156
11157 CONVERT_CHECKED(JSFunction, f, args[0]);
11158 return f->shared()->inferred_name();
11159}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011160
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011161
11162static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011164 AssertNoAllocation no_allocations;
11165
11166 int counter = 0;
11167 int buffer_size = buffer->length();
11168 HeapIterator iterator;
11169 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11170 ASSERT(obj != NULL);
11171 if (!obj->IsSharedFunctionInfo()) {
11172 continue;
11173 }
11174 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11175 if (shared->script() != script) {
11176 continue;
11177 }
11178 if (counter < buffer_size) {
11179 buffer->set(counter, shared);
11180 }
11181 counter++;
11182 }
11183 return counter;
11184}
11185
11186// For a script finds all SharedFunctionInfo's in the heap that points
11187// to this script. Returns JSArray of SharedFunctionInfo wrapped
11188// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011189RUNTIME_FUNCTION(MaybeObject*,
11190 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011191 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011192 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011193 CONVERT_CHECKED(JSValue, script_value, args[0]);
11194
11195 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11196
11197 const int kBufferSize = 32;
11198
11199 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011201 int number = FindSharedFunctionInfosForScript(*script, *array);
11202 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011204 FindSharedFunctionInfosForScript(*script, *array);
11205 }
11206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011208 result->set_length(Smi::FromInt(number));
11209
11210 LiveEdit::WrapSharedFunctionInfos(result);
11211
11212 return *result;
11213}
11214
11215// For a script calculates compilation information about all its functions.
11216// The script source is explicitly specified by the second argument.
11217// The source of the actual script is not used, however it is important that
11218// all generated code keeps references to this particular instance of script.
11219// Returns a JSArray of compilation infos. The array is ordered so that
11220// each function with all its descendant is always stored in a continues range
11221// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011222RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011223 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011224 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011225 CONVERT_CHECKED(JSValue, script, args[0]);
11226 CONVERT_ARG_CHECKED(String, source, 1);
11227 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11228
11229 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011232 return Failure::Exception();
11233 }
11234
11235 return result;
11236}
11237
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011238// Changes the source of the script to a new_source.
11239// If old_script_name is provided (i.e. is a String), also creates a copy of
11240// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011241RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011242 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011244 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11245 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011246 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011247
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011248 CONVERT_CHECKED(Script, original_script_pointer,
11249 original_script_value->value());
11250 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011251
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011252 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11253 new_source,
11254 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011255
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011256 if (old_script->IsScript()) {
11257 Handle<Script> script_handle(Script::cast(old_script));
11258 return *(GetScriptWrapper(script_handle));
11259 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011260 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011261 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011262}
11263
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011265RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011266 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011267 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011268 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11269 return LiveEdit::FunctionSourceUpdated(shared_info);
11270}
11271
11272
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011273// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011274RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011275 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011277 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11278 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11279
ager@chromium.orgac091b72010-05-05 07:34:42 +000011280 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011281}
11282
11283// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011284RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011285 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 HandleScope scope(isolate);
11287 Handle<Object> function_object(args[0], isolate);
11288 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011289
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011290 if (function_object->IsJSValue()) {
11291 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11292 if (script_object->IsJSValue()) {
11293 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011295 }
11296
11297 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11298 } else {
11299 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11300 // and we check it in this function.
11301 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011304}
11305
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011306
11307// In a code of a parent function replaces original function as embedded object
11308// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011309RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011310 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011312
11313 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11314 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11315 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11316
11317 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11318 subst_wrapper);
11319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011320 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011321}
11322
11323
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011324// Updates positions of a shared function info (first parameter) according
11325// to script source change. Text change is described in second parameter as
11326// array of groups of 3 numbers:
11327// (change_begin, change_end, change_end_new_position).
11328// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011329RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011330 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011331 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011332 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11333 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11334
ager@chromium.orgac091b72010-05-05 07:34:42 +000011335 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011336}
11337
11338
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011339// For array of SharedFunctionInfo's (each wrapped in JSValue)
11340// checks that none of them have activations on stacks (of any thread).
11341// Returns array of the same length with corresponding results of
11342// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011343RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011344 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011346 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011347 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011348
ager@chromium.org357bf652010-04-12 11:30:10 +000011349 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011350}
11351
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011352// Compares 2 strings line-by-line, then token-wise and returns diff in form
11353// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11354// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011355RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011356 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011358 CONVERT_ARG_CHECKED(String, s1, 0);
11359 CONVERT_ARG_CHECKED(String, s2, 1);
11360
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011361 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011362}
11363
11364
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011365// A testing entry. Returns statement position which is the closest to
11366// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011367RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011368 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011369 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011370 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11371 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011373 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011374
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011375 if (code->kind() != Code::FUNCTION &&
11376 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011377 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011378 }
11379
11380 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011381 int closest_pc = 0;
11382 int distance = kMaxInt;
11383 while (!it.done()) {
11384 int statement_position = static_cast<int>(it.rinfo()->data());
11385 // Check if this break point is closer that what was previously found.
11386 if (source_position <= statement_position &&
11387 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011388 closest_pc =
11389 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011390 distance = statement_position - source_position;
11391 // Check whether we can't get any closer.
11392 if (distance == 0) break;
11393 }
11394 it.next();
11395 }
11396
11397 return Smi::FromInt(closest_pc);
11398}
11399
11400
ager@chromium.org357bf652010-04-12 11:30:10 +000011401// Calls specified function with or without entering the debugger.
11402// This is used in unit tests to run code as if debugger is entered or simply
11403// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011404RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011405 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011406 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011407 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11408 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11409
11410 Handle<Object> result;
11411 bool pending_exception;
11412 {
11413 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011414 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011415 &pending_exception);
11416 } else {
11417 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011419 &pending_exception);
11420 }
11421 }
11422 if (!pending_exception) {
11423 return *result;
11424 } else {
11425 return Failure::Exception();
11426 }
11427}
11428
11429
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011430// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011431RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011432 CONVERT_CHECKED(String, arg, args[0]);
11433 SmartPointer<char> flags =
11434 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11435 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011437}
11438
11439
11440// Performs a GC.
11441// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011442RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011443 isolate->heap()->CollectAllGarbage(true);
11444 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011445}
11446
11447
11448// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011449RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011451 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011453 }
11454 return Smi::FromInt(usage);
11455}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011456
11457
11458// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011459RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011460#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011462#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011464#endif
11465}
11466
11467
11468// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011469RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011470#ifdef LIVE_OBJECT_LIST
11471 return LiveObjectList::Capture();
11472#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011474#endif
11475}
11476
11477
11478// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011479RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011480#ifdef LIVE_OBJECT_LIST
11481 CONVERT_SMI_CHECKED(id, args[0]);
11482 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 return success ? isolate->heap()->true_value() :
11484 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011485#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011487#endif
11488}
11489
11490
11491// Generates the response to a debugger request for a dump of the objects
11492// contained in the difference between the captured live object lists
11493// specified by id1 and id2.
11494// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11495// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011496RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011497#ifdef LIVE_OBJECT_LIST
11498 HandleScope scope;
11499 CONVERT_SMI_CHECKED(id1, args[0]);
11500 CONVERT_SMI_CHECKED(id2, args[1]);
11501 CONVERT_SMI_CHECKED(start, args[2]);
11502 CONVERT_SMI_CHECKED(count, args[3]);
11503 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11504 EnterDebugger enter_debugger;
11505 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11506#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011508#endif
11509}
11510
11511
11512// Gets the specified object as requested by the debugger.
11513// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011515#ifdef LIVE_OBJECT_LIST
11516 CONVERT_SMI_CHECKED(obj_id, args[0]);
11517 Object* result = LiveObjectList::GetObj(obj_id);
11518 return result;
11519#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011520 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011521#endif
11522}
11523
11524
11525// Gets the obj id for the specified address if valid.
11526// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011527RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011528#ifdef LIVE_OBJECT_LIST
11529 HandleScope scope;
11530 CONVERT_ARG_CHECKED(String, address, 0);
11531 Object* result = LiveObjectList::GetObjId(address);
11532 return result;
11533#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011535#endif
11536}
11537
11538
11539// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011540RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011541#ifdef LIVE_OBJECT_LIST
11542 HandleScope scope;
11543 CONVERT_SMI_CHECKED(obj_id, args[0]);
11544 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11545 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11546 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11547 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11548 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11549
11550 Handle<JSObject> instance_filter;
11551 if (args[1]->IsJSObject()) {
11552 instance_filter = args.at<JSObject>(1);
11553 }
11554 bool verbose = false;
11555 if (args[2]->IsBoolean()) {
11556 verbose = args[2]->IsTrue();
11557 }
11558 int start = 0;
11559 if (args[3]->IsSmi()) {
11560 start = Smi::cast(args[3])->value();
11561 }
11562 int limit = Smi::kMaxValue;
11563 if (args[4]->IsSmi()) {
11564 limit = Smi::cast(args[4])->value();
11565 }
11566
11567 return LiveObjectList::GetObjRetainers(obj_id,
11568 instance_filter,
11569 verbose,
11570 start,
11571 limit,
11572 filter_obj);
11573#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011575#endif
11576}
11577
11578
11579// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011580RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011581#ifdef LIVE_OBJECT_LIST
11582 HandleScope scope;
11583 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11584 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11585 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11586
11587 Handle<JSObject> instance_filter;
11588 if (args[2]->IsJSObject()) {
11589 instance_filter = args.at<JSObject>(2);
11590 }
11591
11592 Object* result =
11593 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11594 return result;
11595#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011596 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011597#endif
11598}
11599
11600
11601// Generates the response to a debugger request for a list of all
11602// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011603RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011604#ifdef LIVE_OBJECT_LIST
11605 CONVERT_SMI_CHECKED(start, args[0]);
11606 CONVERT_SMI_CHECKED(count, args[1]);
11607 return LiveObjectList::Info(start, count);
11608#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011610#endif
11611}
11612
11613
11614// Gets a dump of the specified object as requested by the debugger.
11615// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011616RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011617#ifdef LIVE_OBJECT_LIST
11618 HandleScope scope;
11619 CONVERT_SMI_CHECKED(obj_id, args[0]);
11620 Object* result = LiveObjectList::PrintObj(obj_id);
11621 return result;
11622#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011624#endif
11625}
11626
11627
11628// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011629RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011630#ifdef LIVE_OBJECT_LIST
11631 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011633#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011635#endif
11636}
11637
11638
11639// Generates the response to a debugger request for a summary of the types
11640// of objects in the difference between the captured live object lists
11641// specified by id1 and id2.
11642// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11643// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011645#ifdef LIVE_OBJECT_LIST
11646 HandleScope scope;
11647 CONVERT_SMI_CHECKED(id1, args[0]);
11648 CONVERT_SMI_CHECKED(id2, args[1]);
11649 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11650
11651 EnterDebugger enter_debugger;
11652 return LiveObjectList::Summarize(id1, id2, filter_obj);
11653#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011655#endif
11656}
11657
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011658#endif // ENABLE_DEBUGGER_SUPPORT
11659
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011660
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011661#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011663 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011664 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011665
11666 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011667 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11668 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011670}
11671
11672
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011673RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011674 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011675 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011676
11677 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011678 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11679 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011681}
11682
11683#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011685// Finds the script object from the script data. NOTE: This operation uses
11686// heap traversal to find the function generated for the source position
11687// for the requested break point. For lazily compiled functions several heap
11688// traversals might be required rendering this operation as a rather slow
11689// operation. However for setting break points which is normally done through
11690// some kind of user interaction the performance is not crucial.
11691static Handle<Object> Runtime_GetScriptFromScriptName(
11692 Handle<String> script_name) {
11693 // Scan the heap for Script objects to find the script with the requested
11694 // script data.
11695 Handle<Script> script;
11696 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011697 HeapObject* obj = NULL;
11698 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 // If a script is found check if it has the script data requested.
11700 if (obj->IsScript()) {
11701 if (Script::cast(obj)->name()->IsString()) {
11702 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11703 script = Handle<Script>(Script::cast(obj));
11704 }
11705 }
11706 }
11707 }
11708
11709 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711
11712 // Return the script found.
11713 return GetScriptWrapper(script);
11714}
11715
11716
11717// Get the script object from script data. NOTE: Regarding performance
11718// see the NOTE for GetScriptFromScriptData.
11719// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011720RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722
11723 ASSERT(args.length() == 1);
11724
11725 CONVERT_CHECKED(String, script_name, args[0]);
11726
11727 // Find the requested script.
11728 Handle<Object> result =
11729 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11730 return *result;
11731}
11732
11733
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011734// Determines whether the given stack frame should be displayed in
11735// a stack trace. The caller is the error constructor that asked
11736// for the stack trace to be collected. The first time a construct
11737// call to this function is encountered it is skipped. The seen_caller
11738// in/out parameter is used to remember if the caller has been seen
11739// yet.
11740static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11741 bool* seen_caller) {
11742 // Only display JS frames.
11743 if (!raw_frame->is_java_script())
11744 return false;
11745 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11746 Object* raw_fun = frame->function();
11747 // Not sure when this can happen but skip it just in case.
11748 if (!raw_fun->IsJSFunction())
11749 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011750 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011751 *seen_caller = true;
11752 return false;
11753 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011754 // Skip all frames until we've seen the caller. Also, skip the most
11755 // obvious builtin calls. Some builtin calls (such as Number.ADD
11756 // which is invoked using 'call') are very difficult to recognize
11757 // so we're leaving them in for now.
11758 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011759}
11760
11761
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011762// Collect the raw data for a stack trace. Returns an array of 4
11763// element segments each containing a receiver, function, code and
11764// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011765RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011766 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011767 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011768 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770 HandleScope scope(isolate);
11771 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011772
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011773 limit = Max(limit, 0); // Ensure that limit is not negative.
11774 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011775 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011777
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011778 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011779 // If the caller parameter is a function we skip frames until we're
11780 // under it before starting to collect.
11781 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011782 int cursor = 0;
11783 int frames_seen = 0;
11784 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011785 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011786 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011787 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011788 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011789 // Set initial size to the maximum inlining level + 1 for the outermost
11790 // function.
11791 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011792 frame->Summarize(&frames);
11793 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011794 if (cursor + 4 > elements->length()) {
11795 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11796 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011797 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011798 for (int i = 0; i < cursor; i++) {
11799 new_elements->set(i, elements->get(i));
11800 }
11801 elements = new_elements;
11802 }
11803 ASSERT(cursor + 4 <= elements->length());
11804
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011805 Handle<Object> recv = frames[i].receiver();
11806 Handle<JSFunction> fun = frames[i].function();
11807 Handle<Code> code = frames[i].code();
11808 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011809 elements->set(cursor++, *recv);
11810 elements->set(cursor++, *fun);
11811 elements->set(cursor++, *code);
11812 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011813 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011814 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011815 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011816 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011818 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011819 return *result;
11820}
11821
11822
ager@chromium.org3811b432009-10-28 14:53:37 +000011823// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011824RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011825 ASSERT_EQ(args.length(), 0);
11826
11827 NoHandleAllocation ha;
11828
11829 const char* version_string = v8::V8::GetVersion();
11830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11832 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011833}
11834
11835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011836RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 ASSERT(args.length() == 2);
11838 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11839 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 OS::Abort();
11842 UNREACHABLE();
11843 return NULL;
11844}
11845
11846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011847RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011848 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011849 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011850 Object* key = args[1];
11851
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011852 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011853 Object* o = cache->get(finger_index);
11854 if (o == key) {
11855 // The fastest case: hit the same place again.
11856 return cache->get(finger_index + 1);
11857 }
11858
11859 for (int i = finger_index - 2;
11860 i >= JSFunctionResultCache::kEntriesIndex;
11861 i -= 2) {
11862 o = cache->get(i);
11863 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011864 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011865 return cache->get(i + 1);
11866 }
11867 }
11868
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011869 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011870 ASSERT(size <= cache->length());
11871
11872 for (int i = size - 2; i > finger_index; i -= 2) {
11873 o = cache->get(i);
11874 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011875 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011876 return cache->get(i + 1);
11877 }
11878 }
11879
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011880 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011882
11883 Handle<JSFunctionResultCache> cache_handle(cache);
11884 Handle<Object> key_handle(key);
11885 Handle<Object> value;
11886 {
11887 Handle<JSFunction> factory(JSFunction::cast(
11888 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11889 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011891 // This handle is nor shared, nor used later, so it's safe.
11892 Object** argv[] = { key_handle.location() };
11893 bool pending_exception = false;
11894 value = Execution::Call(factory,
11895 receiver,
11896 1,
11897 argv,
11898 &pending_exception);
11899 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011900 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011901
11902#ifdef DEBUG
11903 cache_handle->JSFunctionResultCacheVerify();
11904#endif
11905
11906 // Function invocation may have cleared the cache. Reread all the data.
11907 finger_index = cache_handle->finger_index();
11908 size = cache_handle->size();
11909
11910 // If we have spare room, put new data into it, otherwise evict post finger
11911 // entry which is likely to be the least recently used.
11912 int index = -1;
11913 if (size < cache_handle->length()) {
11914 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11915 index = size;
11916 } else {
11917 index = finger_index + JSFunctionResultCache::kEntrySize;
11918 if (index == cache_handle->length()) {
11919 index = JSFunctionResultCache::kEntriesIndex;
11920 }
11921 }
11922
11923 ASSERT(index % 2 == 0);
11924 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11925 ASSERT(index < cache_handle->length());
11926
11927 cache_handle->set(index, *key_handle);
11928 cache_handle->set(index + 1, *value);
11929 cache_handle->set_finger_index(index);
11930
11931#ifdef DEBUG
11932 cache_handle->JSFunctionResultCacheVerify();
11933#endif
11934
11935 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011936}
11937
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011939RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011940 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011941 CONVERT_ARG_CHECKED(String, type, 0);
11942 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 return *isolate->factory()->NewJSMessageObject(
11944 type,
11945 arguments,
11946 0,
11947 0,
11948 isolate->factory()->undefined_value(),
11949 isolate->factory()->undefined_value(),
11950 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011951}
11952
11953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011955 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11956 return message->type();
11957}
11958
11959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011960RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011961 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11962 return message->arguments();
11963}
11964
11965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011966RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011967 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11968 return Smi::FromInt(message->start_position());
11969}
11970
11971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011972RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011973 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11974 return message->script();
11975}
11976
11977
kasper.lund44510672008-07-25 07:37:58 +000011978#ifdef DEBUG
11979// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11980// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011981RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011982 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011983 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011984#define COUNT_ENTRY(Name, argc, ressize) + 1
11985 int entry_count = 0
11986 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11987 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11988 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11989#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011990 Factory* factory = isolate->factory();
11991 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011993 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011994#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995 { \
11996 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011997 Handle<String> name; \
11998 /* Inline runtime functions have an underscore in front of the name. */ \
11999 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012000 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012001 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12002 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012004 Vector<const char>(#Name, StrLength(#Name))); \
12005 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012007 pair_elements->set(0, *name); \
12008 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012010 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012012 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012013 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012014 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012015 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012016 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012018 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020 return *result;
12021}
kasper.lund44510672008-07-25 07:37:58 +000012022#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023
12024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012025RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012026 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012027 CONVERT_CHECKED(String, format, args[0]);
12028 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012029 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 LOGGER->LogRuntime(chars, elms);
12031 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012032}
12033
12034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012035RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036 UNREACHABLE(); // implemented as macro in the parser
12037 return NULL;
12038}
12039
12040
12041// ----------------------------------------------------------------------------
12042// Implementation of Runtime
12043
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012044#define F(name, number_of_args, result_size) \
12045 { Runtime::k##name, Runtime::RUNTIME, #name, \
12046 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012047
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012048
12049#define I(name, number_of_args, result_size) \
12050 { Runtime::kInline##name, Runtime::INLINE, \
12051 "_" #name, NULL, number_of_args, result_size },
12052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012055 INLINE_FUNCTION_LIST(I)
12056 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057};
12058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012060MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12061 Object* dictionary) {
12062 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012063 ASSERT(dictionary != NULL);
12064 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12065 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012066 Object* name_symbol;
12067 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012068 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012069 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12070 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012071 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012072 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12073 String::cast(name_symbol),
12074 Smi::FromInt(i),
12075 PropertyDetails(NONE, NORMAL));
12076 if (!maybe_dictionary->ToObject(&dictionary)) {
12077 // Non-recoverable failure. Calling code must restart heap
12078 // initialization.
12079 return maybe_dictionary;
12080 }
12081 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012082 }
12083 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084}
12085
12086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012087const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12088 Heap* heap = name->GetHeap();
12089 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012090 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012091 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012092 int function_index = Smi::cast(smi_index)->value();
12093 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094 }
12095 return NULL;
12096}
12097
12098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012100 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12101}
12102
12103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012104void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012105 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012107 if (failure->IsRetryAfterGC()) {
12108 // Try to do a garbage collection; ignore it if it fails. The C
12109 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012110 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012111 } else {
12112 // Handle last resort GC and make sure to allow future allocations
12113 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012114 isolate->counters()->gc_last_resort_from_js()->Increment();
12115 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117}
12118
12119
12120} } // namespace v8::internal